0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-16 18:37:50 +00:00

Windows Support Phase 1 ()

* abstraction layer for O/S

* updates

* updates

* updates

* temp fix for protobuf

* emulated waitid()

* fix

* fix

* compatibility layer

* fix for idtype

* fix for missing includes

* fix for missing includes

* added missing includes

* added missing includes

* added missing includes

* added missing includes

* added missing includes

* added missing includes

* UUID renamed to ND_UUID to avoid conflict with windows.h

* include libnetdata.h always - no conflicts

* simplify abstraction headers

* fix missing functions

* fix missing functions

* fix missing functions

* fix missing functions

* rename MSYS to WINDOWS

* moved byteorder.h

* structure for an internal windows plugin

* 1st windows plugin

* working plugin

* fix printf

* Special case windows for protobuf

* remove cygwin, compile both as windows

* log windows libraries used

* fix cmake

* fix protobuf

* compilation

* updated compilation script

* added system.ram

* windows uptime

* perflib

* working perflibdump

* minify dump

* updates to windows plugins, enable ML

* minor compatibility fixes for cygwin and msys

* perflib-dump to its own file

* perflib now indexes names

* improvements to the library; disks module WIP

* API for selectively traversing the metrics

* first working perflib chart: disk.space

* working chart on logical and physical disks

* added windows protocols

* fix datatypes for loops

* tinysleep for native smallest sleep support

* remove libuuid dependency on windows

* fix uuid functions for macos compilation

* fix uuid comparison function

* do not overwrite uuid library functions, define them as aliases to our own

* fixed uuid_unparse functions

* fixed typo

* added perflib processor charts

* updates for compiling without posix emulation

* gather common contexts together

* fix includes on linux

* perflib-memory

* windows mem.available

* Update variable names for protobuf

* network traffic

* add network adapters that have traffic as virtual interfaces

* add -pipe to windows compilation

* reset or overflow flag is now per dimension

* dpc is now counted separately

* verified all perflib fields are processed and no text fields are present in the data

* more common contexts

* fix crash

* do not add system.net multiple times

* install deps update and shortcut

* all threads are now joinable behind the scenes

* fix threads cleanup

* prepare for abstracting threads API

* netdata threads full abstraction from pthreads

* more threads abstraction and cleanup

* more compatibility changes

* fix compiler warnings

* add base-devel to packages

* removed duplicate base-devel

* check for strndup

* check headers in quotes

* fix linux compilation

* fix attribute gnu_printf on macos

* fix for threads on macos

* mingw64 compatibility

* enable compilation on windows clion

* added instructions

* enable cloud

* compatibility fixes

* compatibility fixes

* compatibility fixes

* clion works on windows

* support both MSYSTEM=MSYS and MSYSTEM=MINGW64 for configure

* cleanup and docs

* rename uuid_t to nd_uuid_t to avoid conflict with windows uuid_t

* leftovers uuid_t

* do not include uuid.h on macos

* threads signaled cancellations

* do not install v0 dashboard on windows

* script to install openssh server on windows

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* update openssh installation script

* use cleanup variable instead of pthreads push and pop

* replace all calls to netdata_thread_cleanup_push() and netdata_thread_cleanup_pop() with __attribute__((cleanup(...)))

* remove left-over freez

* make sure there are no locks acquired at thread exit

* add missing parameter

* stream receivers and senders are now voluntarily cancelled

* plugins.d now voluntarily exits its threads

* uuid_t may not be aligned to word boundaries - fix the uuid_t functions to work on unaligned objects too.

* collectors evloop is now using the new threading cancellation; ml is now not using pthread_cancel; more fixes

* eliminate threads cancellability from the code base

* fix exit timings and logs; fix uv_threads tags

* use SSL_has_pending() only when it is available

* do not use SSL_has_pending()

* dyncfg files on windows escape collon and pipe characters

* fix compilation on older systems

* fix compilation on older systems

* Create windows installer.

The installer will install everything
under C:\netdata by default.

It will:
  - Install msys2 at C:\netdata
  - Install netdata dependencies with pacman
  - Install the agent itself under C:\netdata\opt

You can start the agent by running an MSYS
shell with C:\netdata\msys2_shell.cmd and
then start the agent normally with:

/opt/netdata/usr/sbin/netdata -D

There are a more couple things to work on:

  - Verify publisher.
  - Install all deps not just libuv & protobuf.
  - Figure out how we want to auto-start the agent as a service.
  - Check how to uninstall things.

* fixed typo

* code cleanup

* Create uninstaller

---------

Co-authored-by: vkalintiris <vasilis@netdata.cloud>
This commit is contained in:
Costa Tsaousis 2024-05-16 13:33:00 +03:00 committed by GitHub
parent c401ef6ac4
commit fe06e8495f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
283 changed files with 7477 additions and 2852 deletions
CMakeLists.txt
packaging
src

View file

@ -225,23 +225,51 @@ endif()
# detect OS
#
set(LINUX False)
set(FREEBSD False)
set(MACOS False)
set(LINUX False)
set(FREEBSD False)
set(MACOS False)
set(WINDOWS False)
set(FOREIGN_OS False)
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
set(MACOS True)
set(COMPILED_FOR_MACOS True)
find_library(IOKIT IOKit)
find_library(FOUNDATION Foundation)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
message(INFO " Compiling for MacOS... ")
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD")
set(FREEBSD True)
set(COMPILED_FOR_FREEBSD True)
else()
message(INFO " Compiling for FreeBSD... ")
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
set(LINUX True)
set(COMPILED_FOR_LINUX True)
add_definitions(-D_GNU_SOURCE)
message(INFO " Compiling for Linux... ")
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
set(WINDOWS True)
set(COMPILED_FOR_WINDOWS True)
add_definitions(-D_GNU_SOURCE)
if($ENV{CLION_IDE})
# clion needs these to find the includes
if("${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
if("$ENV{MSYSTEM}" STREQUAL "MSYS")
include_directories(c:/msys64/usr/include)
include_directories(c:/msys64/usr/include/w32api)
elseif("$ENV{MSYSTEM}" STREQUAL "MINGW64")
include_directories(c:/msys64/mingw64/include)
elseif("$ENV{MSYSTEM}" STREQUAL "UCRT64")
include_directories(c:/msys64/ucrt64/include)
endif()
endif()
endif()
message(INFO " Compiling for Windows (${CMAKE_SYSTEM_NAME}, MSYSTEM=$ENV{MSYSTEM})... ")
else()
set(FOREIGN_OS True)
set(COMPILED_FOR_FOREIGN_OS True)
message(WARNING " Compiling for Unknown O/S... (${CMAKE_SYSTEM_NAME})")
endif()
if(ENABLE_PLUGIN_EBPF)
@ -326,6 +354,20 @@ check_include_file("sys/statvfs.h" HAVE_SYS_STATVFS_H)
check_include_file("inttypes.h" HAVE_INTTYPES_H)
check_include_file("stdint.h" HAVE_STDINT_H)
check_include_file("sys/capability.h" HAVE_SYS_CAPABILITY_H)
check_include_file("arpa/inet.h" HAVE_ARPA_INET_H)
check_include_file("netinet/tcp.h" HAVE_NETINET_TCP_H)
check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H)
check_include_file("grp.h" HAVE_GRP_H)
check_include_file("pwd.h" HAVE_PWD_H)
check_include_file("net/if.h" HAVE_NET_IF_H)
check_include_file("poll.h" HAVE_POLL_H)
check_include_file("syslog.h" HAVE_SYSLOG_H)
check_include_file("sys/mman.h" HAVE_SYS_MMAN_H)
check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H)
check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H)
check_include_file("sys/wait.h" HAVE_SYS_WAIT_H)
check_include_file("sys/un.h" HAVE_SYS_UN_H)
check_include_file("spawn.h" HAVE_SPAWN_H)
#
# check symbols
@ -340,9 +382,15 @@ check_symbol_exists(finite "math.h" HAVE_FINITE)
check_symbol_exists(isfinite "math.h" HAVE_ISFINITE)
check_symbol_exists(dlsym "dlfcn.h" HAVE_DLSYM)
check_function_exists(pthread_getthreadid_np HAVE_PTHREAD_GETTHREADID_NP)
check_function_exists(pthread_threadid_np HAVE_PTHREAD_THREADID_NP)
check_function_exists(gettid HAVE_GETTID)
check_function_exists(waitid HAVE_WAITID)
check_function_exists(nice HAVE_NICE)
check_function_exists(recvmmsg HAVE_RECVMMSG)
check_function_exists(getpriority HAVE_GETPRIORITY)
check_function_exists(setenv HAVE_SETENV)
check_function_exists(strndup HAVE_STRNDUP)
check_function_exists(sched_getscheduler HAVE_SCHED_GETSCHEDULER)
check_function_exists(sched_setscheduler HAVE_SCHED_SETSCHEDULER)
@ -624,10 +672,10 @@ set(LIBNETDATA_FILES
src/libnetdata/log/journal.h
src/libnetdata/log/log.c
src/libnetdata/log/log.h
src/libnetdata/os.c
src/libnetdata/os.h
src/libnetdata/os/os.c
src/libnetdata/os/os.h
src/libnetdata/simple_hashtable.h
src/libnetdata/byteorder.h
src/libnetdata/os/byteorder.h
src/libnetdata/onewayalloc/onewayalloc.c
src/libnetdata/onewayalloc/onewayalloc.h
src/libnetdata/popen/popen.c
@ -682,6 +730,34 @@ set(LIBNETDATA_FILES
src/libnetdata/linked-lists.h
src/libnetdata/storage-point.h
src/libnetdata/bitmap64.h
src/libnetdata/os/waitid.c
src/libnetdata/os/waitid.h
src/libnetdata/os/gettid.c
src/libnetdata/os/gettid.h
src/libnetdata/os/adjtimex.c
src/libnetdata/os/adjtimex.h
src/libnetdata/os/setresuid.c
src/libnetdata/os/setresuid.h
src/libnetdata/os/setresgid.c
src/libnetdata/os/setresgid.h
src/libnetdata/os/getgrouplist.c
src/libnetdata/os/getgrouplist.h
src/libnetdata/os/get_pid_max.c
src/libnetdata/os/get_pid_max.h
src/libnetdata/os/os-freebsd-wrappers.c
src/libnetdata/os/os-freebsd-wrappers.h
src/libnetdata/os/os-macos-wrappers.c
src/libnetdata/os/os-macos-wrappers.h
src/libnetdata/os/get_system_cpus.c
src/libnetdata/os/get_system_cpus.h
src/libnetdata/os/tinysleep.c
src/libnetdata/os/tinysleep.h
src/libnetdata/os/uuid_generate.c
src/libnetdata/os/uuid_generate.h
src/libnetdata/os/setenv.c
src/libnetdata/os/setenv.h
src/libnetdata/os/strndup.c
src/libnetdata/os/strndup.h
)
if(ENABLE_PLUGIN_EBPF)
@ -956,6 +1032,16 @@ else()
)
endif()
set(INTERNAL_COLLECTORS_FILES
src/collectors/common-contexts/common-contexts.h
src/collectors/common-contexts/disk.io.h
src/collectors/common-contexts/system.io.h
src/collectors/common-contexts/system.ram.h
src/collectors/common-contexts/mem.swap.h
src/collectors/common-contexts/mem.pgfaults.h
src/collectors/common-contexts/mem.available.h
)
set(PLUGINSD_PLUGIN_FILES
src/collectors/plugins.d/plugins_d.c
src/collectors/plugins.d/plugins_d.h
@ -1197,6 +1283,24 @@ set(FREEBSD_PLUGIN_FILES
src/collectors/proc.plugin/zfs_common.h
)
set(WINDOWS_PLUGIN_FILES
src/collectors/windows.plugin/windows_plugin.c
src/collectors/windows.plugin/windows_plugin.h
src/collectors/windows.plugin/GetSystemUptime.c
src/collectors/windows.plugin/GetSystemRAM.c
src/collectors/windows.plugin/GetSystemCPU.c
src/collectors/windows.plugin/perflib.c
src/collectors/windows.plugin/perflib.h
src/collectors/windows.plugin/perflib-rrd.c
src/collectors/windows.plugin/perflib-rrd.h
src/collectors/windows.plugin/perflib-names.c
src/collectors/windows.plugin/perflib-dump.c
src/collectors/windows.plugin/perflib-storage.c
src/collectors/windows.plugin/perflib-processor.c
src/collectors/windows.plugin/perflib-network.c
src/collectors/windows.plugin/perflib-memory.c
)
set(PROC_PLUGIN_FILES
src/collectors/proc.plugin/ipc.c
src/collectors/proc.plugin/plugin_proc.c
@ -1315,6 +1419,7 @@ if(LINUX)
${PROC_PLUGIN_FILES}
${TC_PLUGIN_FILES}
${TIMEX_PLUGIN_FILES}
${INTERNAL_COLLECTORS_FILES}
)
if(ENABLE_SENTRY)
@ -1327,12 +1432,20 @@ elseif(MACOS)
src/daemon/static_threads_macos.c
${MACOS_PLUGIN_FILES}
${TIMEX_PLUGIN_FILES}
${INTERNAL_COLLECTORS_FILES}
)
elseif(FREEBSD)
list(APPEND NETDATA_FILES
src/daemon/static_threads_freebsd.c
${FREEBSD_PLUGIN_FILES}
${TIMEX_PLUGIN_FILES}
${INTERNAL_COLLECTORS_FILES}
)
elseif(WINDOWS)
list(APPEND NETDATA_FILES
src/daemon/static_threads_windows.c
${WINDOWS_PLUGIN_FILES}
${INTERNAL_COLLECTORS_FILES}
)
endif()
@ -1518,6 +1631,7 @@ target_include_directories(libnetdata BEFORE PUBLIC ${CONFIG_H_DIR} ${CMAKE_SOUR
target_link_libraries(libnetdata PUBLIC
"$<$<NOT:$<BOOL:${HAVE_BUILTIN_ATOMICS}>>:atomic>"
"$<$<OR:$<BOOL:${LINUX}>,$<BOOL:${FREEBSD}>>:pthread;rt>"
"$<$<BOOL:${WINDOWS}>:kernel32;advapi32;winmm;rpcrt4>"
"$<$<BOOL:${LINK_LIBM}>:m>"
"${SYSTEMD_LDFLAGS}")
@ -1578,7 +1692,7 @@ if(LIBBROTLI_FOUND)
endif()
# uuid
if(MACOS)
if(MACOS OR WINDOWS)
# UUID functionality is part of the system libraries here, so no extra
# stuff needed.
else()
@ -1879,9 +1993,9 @@ endif()
if(ENABLE_PLUGIN_CUPS)
pkg_check_modules(CUPS libcups)
if(NOT CUPS_LIBRARIES)
if(NOT CUPS_FOUND)
pkg_check_modules(CUPS cups)
if(NOT CUPS_LIBRARIES)
if(NOT CUPS_FOUND)
find_program(CUPS_CONFIG cups-config)
if(CUPS_CONFIG)
execute_process(COMMAND ${CUPS_CONFIG} --api-version OUTPUT_VARIABLE CUPS_API_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
@ -2914,10 +3028,12 @@ install(FILES
COMPONENT netdata
DESTINATION ${WEB_DEST}/.well-known/dnt)
# v0 dashboard
install(FILES
src/web/gui/v0/index.html
COMPONENT netdata
DESTINATION ${WEB_DEST}/v0)
if(NOT WINDOWS)
# v0 dashboard
install(FILES
src/web/gui/v0/index.html
COMPONENT netdata
DESTINATION ${WEB_DEST}/v0)
endif()
include(Packaging)

View file

@ -56,54 +56,67 @@ endfunction()
# Handle detection of Protobuf
macro(netdata_detect_protobuf)
if(NOT ENABLE_BUNDLED_PROTOBUF)
if (NOT BUILD_SHARED_LIBS)
set(Protobuf_USE_STATIC_LIBS On)
if(COMPILED_FOR_WINDOWS)
set(PROTOBUF_PROTOC_EXECUTABLE "$ENV{PROTOBUF_PROTOC_EXECUTABLE}")
if(NOT PROTOBUF_PROTOC_EXECUTABLE)
set(PROTOBUF_PROTOC_EXECUTABLE "/bin/protoc")
endif()
set(PROTOBUF_CFLAGS_OTHER "")
set(PROTOBUF_INCLUDE_DIRS "")
set(PROTOBUF_LIBRARIES "-lprotobuf")
set(ENABLE_PROTOBUF True)
set(HAVE_PROTOBUF True)
else()
if(NOT ENABLE_BUNDLED_PROTOBUF)
if (NOT BUILD_SHARED_LIBS)
set(Protobuf_USE_STATIC_LIBS On)
endif()
# The FindProtobuf CMake module shipped by upstream CMake is
# broken for Protobuf version 22.0 and newer because it does
# not correctly pull in the new Abseil dependencies. Protobuf
# itself sometimes ships a CMake Package Configuration module
# that _does_ work correctly, so use that in preference to the
# Find module shipped with CMake.
#
# The code below works by first attempting to use find_package
# in config mode, and then checking for the existence of the
# target we actually use that gets defined by the protobuf
# CMake Package Configuration Module to determine if that
# worked. A bit of extra logic is required in the case of the
# config mode working, because some systems ship compatibility
# logic for the old FindProtobuf module while others do not.
#
# Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
find_package(Protobuf CONFIG)
if(NOT TARGET protobuf::libprotobuf)
message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
find_package(Protobuf REQUIRED)
endif()
endif()
# The FindProtobuf CMake module shipped by upstream CMake is
# broken for Protobuf version 22.0 and newer because it does
# not correctly pull in the new Abseil dependencies. Protobuf
# itself sometimes ships a CMake Package Configuration module
# that _does_ work correctly, so use that in preference to the
# Find module shipped with CMake.
#
# The code below works by first attempting to use find_package
# in config mode, and then checking for the existence of the
# target we actually use that gets defined by the protobuf
# CMake Package Configuration Module to determine if that
# worked. A bit of extra logic is required in the case of the
# config mode working, because some systems ship compatibility
# logic for the old FindProtobuf module while others do not.
#
# Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
find_package(Protobuf CONFIG)
if(TARGET protobuf::libprotobuf)
if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
endif()
if(NOT TARGET protobuf::libprotobuf)
message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
find_package(Protobuf REQUIRED)
# It is technically possible that this may still not
# be set by this point, so we need to check it and
# fail noisily if it isn't because the build won't
# work without it.
if(NOT Protobuf_PROTOC_EXECUTABLE)
message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
endif()
set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
endif()
set(ENABLE_PROTOBUF True)
set(HAVE_PROTOBUF True)
endif()
if(TARGET protobuf::libprotobuf)
if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
endif()
# It is technically possible that this may still not
# be set by this point, so we need to check it and
# fail noisily if it isn't because the build won't
# work without it.
if(NOT Protobuf_PROTOC_EXECUTABLE)
message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
endif()
set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
endif()
set(ENABLE_PROTOBUF True)
set(HAVE_PROTOBUF True)
endmacro()
# Helper function to compile protocol definitions into C++ code.

View file

@ -12,6 +12,8 @@
#cmakedefine COMPILED_FOR_FREEBSD
#cmakedefine COMPILED_FOR_LINUX
#cmakedefine COMPILED_FOR_MACOS
#cmakedefine COMPILED_FOR_WINDOWS
#cmakedefine COMPILED_FOR_FOREIGN_OS
// checked headers
@ -28,6 +30,20 @@
#cmakedefine HAVE_INTTYPES_H
#cmakedefine HAVE_STDINT_H
#cmakedefine HAVE_SYS_CAPABILITY_H
#cmakedefine HAVE_ARPA_INET_H
#cmakedefine HAVE_NETINET_TCP_H
#cmakedefine HAVE_SYS_IOCTL_H
#cmakedefine HAVE_GRP_H
#cmakedefine HAVE_PWD_H
#cmakedefine HAVE_NET_IF_H
#cmakedefine HAVE_POLL_H
#cmakedefine HAVE_SYSLOG_H
#cmakedefine HAVE_SYS_MMAN_H
#cmakedefine HAVE_SYS_RESOURCE_H
#cmakedefine HAVE_SYS_SOCKET_H
#cmakedefine HAVE_SYS_WAIT_H
#cmakedefine HAVE_SYS_UN_H
#cmakedefine HAVE_SPAWN_H
#cmakedefine HAVE_CAPABILITY
#cmakedefine HAVE_PROTOBUF
@ -44,8 +60,13 @@
#cmakedefine HAVE_FINITE
#cmakedefine HAVE_ISFINITE
#cmakedefine HAVE_RECVMMSG
#cmakedefine HAVE_PTHREAD_GETTHREADID_NP
#cmakedefine HAVE_PTHREAD_THREADID_NP
#cmakedefine HAVE_GETTID
#cmakedefine HAVE_WAITID
#cmakedefine HAVE_NICE
#cmakedefine HAVE_GETPRIORITY
#cmakedefine HAVE_SETENV
#cmakedefine HAVE_DLSYM
#cmakedefine HAVE_BACKTRACE
@ -70,6 +91,8 @@
#cmakedefine HAVE_C__GENERIC
#cmakedefine HAVE_C_MALLOPT
#cmakedefine HAVE_SETNS
#cmakedefine HAVE_STRNDUP
#cmakedefine SSL_HAS_PENDING
#cmakedefine HAVE_FUNC_ATTRIBUTE_FORMAT
#cmakedefine HAVE_FUNC_ATTRIBUTE_MALLOC

View file

@ -0,0 +1,19 @@
#!/usr/bin/bash
convert_path() {
local ARG="$1"
ARG="${ARG//C:\\//c/}"
ARG="${ARG//c:\\//c/}"
ARG="${ARG//C:\///c/}"
ARG="${ARG//c:\///c/}"
echo "$ARG"
}
declare params=()
for x in "${@}"
do
params+=("$(convert_path "${x}")")
done
"${params[@]}"

View file

@ -0,0 +1,17 @@
@echo off
:: In Clion Toolchains
:: 1. Add a MinGW profile
:: 2. Set Toolset to C:\msys64\mingw64
:: 3. Add environment and set the full path to this file, like:
:: C:\msys64\home\costa\src\netdata-ktsaou.git\packaging\utils\clion-mingw64-environment.bat
:: 4. Let everything else to Bundled and auto-detected
::
set "batch_dir=%~dp0"
set "batch_dir=%batch_dir:\=/%"
set MSYSTEM=MINGW64
set GOROOT=C:\msys64\mingw64
set PATH="%PATH%;C:\msys64\mingw64\bin;C:\msys64\usr\bin;C:\msys64\bin"
::set PKG_CONFIG_EXECUTABLE=C:\msys64\mingw64\bin\pkg-config.exe
::set CMAKE_C_COMPILER=C:\msys64\mingw64\bin\gcc.exe
::set CMAKE_CC_COMPILER=C:\msys64\mingw64\bin\g++.exe
set PROTOBUF_PROTOC_EXECUTABLE=C:/msys64/mingw64/bin/protoc.exe

View file

@ -0,0 +1,20 @@
@echo off
:: In Clion Toolchains
:: 1. Add a MinGW profile
:: 2. Set Toolset to C:\msys64\mingw64
:: 3. Add environment and set the full path to this file, like:
:: C:\msys64\home\costa\src\netdata-ktsaou.git\packaging\utils\clion-mingw64-environment.bat
:: 4. Let everything else to Bundled and auto-detected
::
set "batch_dir=%~dp0"
set "batch_dir=%batch_dir:\=/%"
set MSYSTEM=MSYS
:: go exists only mingw64 / ucrt64 / etc, not under msys profile
set GOROOT=C:\msys64\mingw64
set PATH="%PATH%;C:\msys64\usr\bin;C:\msys64\bin;C:\msys64\mingw64\bin"
::set PKG_CONFIG_EXECUTABLE=C:\msys64\mingw64\bin\pkg-config.exe
::set CMAKE_C_COMPILER=C:\msys64\mingw64\bin\gcc.exe
::set CMAKE_CC_COMPILER=C:\msys64\mingw64\bin\g++.exe
set PROTOBUF_PROTOC_EXECUTABLE=%batch_dir%/protoc.bat

View file

@ -0,0 +1,71 @@
#!/bin/sh
# On MSYS2, install these dependencies to build netdata:
install_dependencies() {
pacman -S \
git cmake ninja base-devel msys2-devel \
libyaml-devel libzstd-devel libutil-linux libutil-linux-devel \
mingw-w64-x86_64-toolchain mingw-w64-ucrt-x86_64-toolchain \
mingw64/mingw-w64-x86_64-mold ucrt64/mingw-w64-ucrt-x86_64-mold \
msys/gdb ucrt64/mingw-w64-ucrt-x86_64-gdb mingw64/mingw-w64-x86_64-gdb \
msys/zlib-devel mingw64/mingw-w64-x86_64-zlib ucrt64/mingw-w64-ucrt-x86_64-zlib \
msys/libuv-devel ucrt64/mingw-w64-ucrt-x86_64-libuv mingw64/mingw-w64-x86_64-libuv \
liblz4-devel mingw64/mingw-w64-x86_64-lz4 ucrt64/mingw-w64-ucrt-x86_64-lz4 \
openssl-devel mingw64/mingw-w64-x86_64-openssl ucrt64/mingw-w64-ucrt-x86_64-openssl \
protobuf-devel mingw64/mingw-w64-x86_64-protobuf ucrt64/mingw-w64-ucrt-x86_64-protobuf \
msys/pcre2-devel mingw64/mingw-w64-x86_64-pcre2 ucrt64/mingw-w64-ucrt-x86_64-pcre2 \
msys/brotli-devel mingw64/mingw-w64-x86_64-brotli ucrt64/mingw-w64-ucrt-x86_64-brotli \
msys/ccache ucrt64/mingw-w64-ucrt-x86_64-ccache mingw64/mingw-w64-x86_64-ccache \
mingw64/mingw-w64-x86_64-go ucrt64/mingw-w64-ucrt-x86_64-go
}
if [ "${1}" = "install" ]
then
install_dependencies || exit 1
exit 0
fi
export PATH="/usr/local/bin:${PATH}"
WT_ROOT="$(pwd)"
BUILD_TYPE="Debug"
NULL=""
if [ -z "${MSYSTEM}" ]; then
build="${WT_ROOT}/build-${OSTYPE}"
else
build="${WT_ROOT}/build-${OSTYPE}-${MSYSTEM}"
fi
if [ "$USER" = "vk" ]; then
build="${WT_ROOT}/build"
fi
set -exu -o pipefail
if [ -d "${build}" ]
then
rm -rf "${build}"
fi
/usr/bin/cmake -S "${WT_ROOT}" -B "${build}" \
-G Ninja \
-DCMAKE_INSTALL_PREFIX="/opt/netdata" \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-DCMAKE_C_FLAGS="-O0 -ggdb -Wall -Wextra -Wno-char-subscripts -Wa,-mbig-obj -pipe -DNETDATA_INTERNAL_CHECKS=1 -D_FILE_OFFSET_BITS=64 -D__USE_MINGW_ANSI_STDIO=1" \
-DNETDATA_USER="${USER}" \
-DDEFAULT_FEATURE_STATE=Off \
-DENABLE_H2O=Off \
-DENABLE_LOGS_MANAGEMENT_TESTS=Off \
-DENABLE_ACLK=On \
-DENABLE_CLOUD=On \
-DENABLE_ML=On \
-DENABLE_BUNDLED_JSONC=On \
-DENABLE_BUNDLED_PROTOBUF=Off \
${NULL}
ninja -v -C "${build}" || ninja -v -C "${build}" -j 1
echo
echo "Compile with:"
echo "ninja -v -C \"${build}\" || ninja -v -C \"${build}\" -j 1"

View file

@ -0,0 +1,34 @@
Outfile "netdata-installer.exe"
InstallDir "C:\netdata"
RequestExecutionLevel admin
Section
SetOutPath $INSTDIR
WriteUninstaller $INSTDIR\uninstaller.exe
SectionEnd
Section "Install MSYS2 environment"
SetOutPath $TEMP
SetCompress off
File "C:\msys64\msys2-installer.exe"
nsExec::ExecToLog 'cmd.exe /C "$TEMP\msys2-installer.exe" in --confirm-command --accept-messages --root $INSTDIR'
Delete "$TEMP\msys2-installer.exe"
SectionEnd
Section "Install MSYS2 packages"
ExecWait '"$INSTDIR\usr\bin\bash.exe" -lc "pacman -S --noconfirm msys/libuv msys/protobuf"'
SectionEnd
Section "Install Netdata"
SetOutPath $INSTDIR\opt\netdata
SetCompress off
File /r "C:\msys64\opt\netdata\*.*"
SectionEnd
Section "Uninstall"
nsExec::ExecToLog 'cmd.exe /C "$INSTDIR\uninstall.exe" pr --confirm-command'
SectionEnd

View file

@ -0,0 +1,27 @@
#!/bin/sh
export PATH="/usr/local/bin:${PATH}"
WT_ROOT="$(pwd)"
NULL=""
if [ -z "${MSYSTEM}" ]; then
build="${WT_ROOT}/build-${OSTYPE}"
else
build="${WT_ROOT}/build-${OSTYPE}-${MSYSTEM}"
fi
if [ "$USER" = "vk" ]; then
build="${WT_ROOT}/build"
fi
set -exu -o pipefail
ninja -v -C "${build}" install
if [ ! -f "/msys2-installer.exe" ]; then
wget -O /msys2-installer.exe \
"https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe"
fi
makensis "${WT_ROOT}/packaging/utils/installer.nsi"

View file

@ -0,0 +1,9 @@
@echo off
::
:: The problem with /usr/bin/protoc is that it accepts colon separated (:) paths at its parameters.
:: This makes C:/ being parsed as 2 paths: C and /, which of course both fail.
:: To overcome this problem, we use bash_execute.sh, which replaces all occurences of C: with /c.
::
set "batch_dir=%~dp0"
set "batch_dir=%batch_dir:\=/%"
C:\msys64\usr\bin\bash.exe %batch_dir%/bash_execute.sh protoc %*

View file

@ -0,0 +1,118 @@
@echo off
::
:: This script will:
::
:: 1. install the windows OpenSSH server (either via dsim or download it)
:: 2. activate the windows OpenSSH service
:: 3. open OpenSSH TCP port at windows firewall
:: 4. create a small batch file to start an MSYS session
:: 5. Set the default OpenSSH startup script to start the MSYS session
::
:: Problems:
:: On older windows versions, terminal emulation is broken.
:: So, on windows 10 or windows server before 2019, the ssh session
:: will not have proper terminal emulation and will be not be able to
:: be used for editing files.
:: For more info check:
:: https://github.com/PowerShell/Win32-OpenSSH/issues/1260
::
:: Check if OpenSSH Server is already installed
sc query sshd >nul 2>&1
if %errorlevel% neq 0 (
echo "OpenSSH Server not found. Attempting to install via dism..."
goto :install_openssh_dism
) else (
echo "OpenSSH Server is already installed."
goto :configure_openssh
)
:: Install OpenSSH using dism
:install_openssh_dism
dism /online /Enable-Feature /FeatureName:OpenSSH-Client /All >nul 2>&1
dism /online /Enable-Feature /FeatureName:OpenSSH-Server /All >nul 2>&1
:: Check if dism succeeded in installing OpenSSH
sc query sshd >nul 2>&1
if %errorlevel% neq 0 (
echo "OpenSSH installation via dism failed or is unavailable."
goto :install_openssh_manual
) else (
echo "OpenSSH installed successfully using dism."
goto :configure_openssh
)
:: Function to Install OpenSSH manually if dism fails
:install_openssh_manual
echo "Installing OpenSSH manually..."
:: Download the latest OpenSSH release
set DOWNLOAD_URL=https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.5.0.0p1-Beta/OpenSSH-Win64.zip
set DOWNLOAD_FILE=%temp%\OpenSSH-Win64.zip
set INSTALL_DIR=C:\Program Files\OpenSSH-Win64
:: Create the installation directory if it doesn't exist
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
:: Attempt to download OpenSSH using Invoke-WebRequest and TLS configuration
powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; try { Invoke-WebRequest -Uri '%DOWNLOAD_URL%' -OutFile '%DOWNLOAD_FILE%' -UseBasicParsing; exit 0 } catch { exit 1 }"
if %errorlevel% neq 0 (
echo "Invoke-WebRequest download failed. Attempting to download using curl..."
curl -L -o "%DOWNLOAD_FILE%" "%DOWNLOAD_URL%"
if %errorlevel% neq 0 (
echo "Failed to download OpenSSH using curl. Exiting..."
exit /b 1
)
)
:: Unzip directly to INSTALL_DIR (flatten the folder structure)
powershell -Command "Expand-Archive -Path '%DOWNLOAD_FILE%' -DestinationPath '%INSTALL_DIR%' -Force"
if %errorlevel% neq 0 (
echo "Failed to unzip OpenSSH package."
exit /b 1
)
:: Move inner contents to INSTALL_DIR if nested OpenSSH-Win64 folder exists
if exist "%INSTALL_DIR%\OpenSSH-Win64" (
xcopy "%INSTALL_DIR%\OpenSSH-Win64\*" "%INSTALL_DIR%\" /s /e /y
rmdir "%INSTALL_DIR%\OpenSSH-Win64" /s /q
)
:: Add the OpenSSH binaries to the system PATH
setx /M PATH "%INSTALL_DIR%;%PATH%"
:: Register OpenSSH utilities as services using PowerShell
powershell -ExecutionPolicy Bypass -Command "& '%INSTALL_DIR%\install-sshd.ps1'"
:: Verify if manual installation succeeded
sc query sshd >nul 2>&1
if %errorlevel% neq 0 (
echo "Manual OpenSSH installation failed. Exiting..."
exit /b 1
) else (
echo "OpenSSH installed successfully manually."
goto :configure_openssh
)
:configure_openssh
:: Ensure OpenSSH Server service is set to start automatically and start the service
sc config sshd start= auto
net start sshd
:: Create msys2.bat file with specific content
set MSYS2_PATH=C:\msys64
if not exist "%MSYS2_PATH%" (
echo "Error: %MSYS2_PATH% does not exist."
exit /b 1
)
echo @%MSYS2_PATH%\msys2_shell.cmd -defterm -here -no-start -msys > %MSYS2_PATH%\msys2.bat
:: Run PowerShell command to set default shell
powershell -Command "New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name 'DefaultShell' -Value '%MSYS2_PATH%\msys2.bat' -PropertyType String -Force"
:: Open the Windows Firewall for sshd (using PowerShell)
powershell -Command "New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd) Incoming' -Description 'Allow incoming SSH traffic via OpenSSH server' -Enabled True -Direction Inbound -Protocol TCP -LocalPort 22 -Action Allow"
echo "OpenSSH has been successfully configured with MSYS2 as the default shell, and the firewall has been opened for sshd."
pause

View file

@ -817,10 +817,6 @@ void *aclk_main(void *ptr)
unsigned int proto_hdl_cnt = aclk_init_rx_msg_handlers();
// This thread is unusual in that it cannot be cancelled by cancel_main_threads()
// as it must notify the far end that it shutdown gracefully and avoid the LWT.
netdata_thread_disable_cancelability();
#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
nd_log(NDLS_DAEMON, NDLP_INFO,
"Killing ACLK thread -> cloud functionality has been disabled");
@ -861,13 +857,10 @@ void *aclk_main(void *ptr)
aclk_stats_enabled = config_get_boolean(CONFIG_SECTION_CLOUD, "statistics", global_statistics_enabled);
if (aclk_stats_enabled) {
stats_thread = callocz(1, sizeof(struct aclk_stats_thread));
stats_thread->thread = mallocz(sizeof(netdata_thread_t));
stats_thread->query_thread_count = query_threads.count;
stats_thread->client = mqttwss_client;
aclk_stats_thread_prepare(query_threads.count, proto_hdl_cnt);
netdata_thread_create(
stats_thread->thread, "ACLK_STATS", NETDATA_THREAD_OPTION_JOINABLE, aclk_stats_main_thread,
stats_thread);
stats_thread->thread = nd_thread_create("ACLK_STATS", NETDATA_THREAD_OPTION_JOINABLE, aclk_stats_main_thread, stats_thread);
}
// Keep reconnecting and talking until our time has come
@ -901,9 +894,8 @@ exit_full:
aclk_query_threads_cleanup(&query_threads);
if (aclk_stats_enabled) {
netdata_thread_join(*stats_thread->thread, NULL);
nd_thread_join(stats_thread->thread);
aclk_stats_thread_cleanup();
freez(stats_thread->thread);
freez(stats_thread);
}
free_topic_cache();
@ -919,7 +911,7 @@ exit:
void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
{
uuid_t node_id;
nd_uuid_t node_id;
int ret = 0;
if (!aclk_connected)
@ -1165,7 +1157,7 @@ char *aclk_state(void)
buffer_strcat(wb, "\n\tAlert Streaming Status:");
fill_alert_status_for_host(wb, host);
}
rrd_unlock();
rrd_rdunlock();
}
ret = strdupz(buffer_tostring(wb));
@ -1315,7 +1307,7 @@ char *aclk_state_json(void)
json_object_array_add(grp, nodeinstance);
}
rrd_unlock();
rrd_rdunlock();
json_object_object_add(msg, "node-instances", grp);
char *str = strdupz(json_object_to_json_string_ext(msg, JSON_C_TO_STRING_PLAIN));

View file

@ -351,8 +351,11 @@ void aclk_query_threads_start(struct aclk_query_threads *query_threads, mqtt_wss
if(unlikely(snprintfz(thread_name, TASK_LEN_MAX, "ACLK_QRY[%d]", i) < 0))
netdata_log_error("snprintf encoding error");
netdata_thread_create(
&query_threads->thread_list[i].thread, thread_name, NETDATA_THREAD_OPTION_JOINABLE, aclk_query_main_thread,
query_threads->thread_list[i].thread = nd_thread_create(
thread_name,
NETDATA_THREAD_OPTION_JOINABLE,
aclk_query_main_thread,
&query_threads->thread_list[i]);
}
}
@ -361,7 +364,7 @@ void aclk_query_threads_cleanup(struct aclk_query_threads *query_threads)
{
if (query_threads && query_threads->thread_list) {
for (int i = 0; i < query_threads->count; i++) {
netdata_thread_join(query_threads->thread_list[i].thread, NULL);
nd_thread_join(query_threads->thread_list[i].thread);
}
freez(query_threads->thread_list);
}

View file

@ -18,7 +18,7 @@ extern pthread_mutex_t query_lock_wait;
//extern volatile int aclk_connected;
struct aclk_query_thread {
netdata_thread_t thread;
ND_THREAD *thread;
int idx;
mqtt_wss_client client;
};

View file

@ -255,7 +255,7 @@ int create_node_instance_result(const char *msg, size_t msg_len)
netdata_log_debug(D_ACLK, "CreateNodeInstanceResult: guid:%s nodeid:%s", res.machine_guid, res.node_id);
uuid_t host_id, node_id;
nd_uuid_t host_id, node_id;
if (uuid_parse(res.machine_guid, host_id)) {
netdata_log_error("Error parsing machine_guid provided by CreateNodeInstanceResult");
freez(res.machine_guid);

View file

@ -387,11 +387,12 @@ void *aclk_stats_main_thread(void *ptr)
struct aclk_metrics permanent;
while (service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) {
netdata_thread_testcancel();
// ------------------------------------------------------------------------
// Wait for the next iteration point.
heartbeat_next(&hb, step_ut);
if (!service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) break;
ACLK_STATS_LOCK;

View file

@ -19,7 +19,7 @@ extern netdata_mutex_t aclk_stats_mutex;
int aclk_cloud_req_http_type_to_idx(const char *name);
struct aclk_stats_thread {
netdata_thread_t *thread;
ND_THREAD *thread;
int query_thread_count;
mqtt_wss_client client;
};

View file

@ -101,7 +101,7 @@ static int aclk_send_message_with_bin_payload(mqtt_wss_client client, json_objec
*/
static struct json_object *create_hdr(const char *type, const char *msg_id, time_t ts_secs, usec_t ts_us, int version)
{
uuid_t uuid;
nd_uuid_t uuid;
char uuid_str[36 + 1];
json_object *tmp;
json_object *obj = json_object_new_object();

View file

@ -150,7 +150,7 @@ void load_claiming_state(void)
#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
netdata_cloud_enabled = false;
#else
uuid_t uuid;
nd_uuid_t uuid;
// Propagate into aclk and registry. Be kind of atomic...
appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", DEFAULT_CLOUD_BASE_URL);
@ -240,7 +240,7 @@ void load_cloud_conf(int silent)
}
static char *netdata_random_session_id_filename = NULL;
static uuid_t netdata_random_session_id = { 0 };
static nd_uuid_t netdata_random_session_id = { 0 };
bool netdata_random_session_id_generate(void) {
static char guid[UUID_STR_LEN] = "";
@ -291,7 +291,7 @@ bool netdata_random_session_id_matches(const char *guid) {
if(uuid_is_null(netdata_random_session_id))
return false;
uuid_t uuid;
nd_uuid_t uuid;
if(uuid_parse(guid, uuid))
return false;
@ -306,7 +306,7 @@ static bool check_claim_param(const char *s) {
if(!s || !*s) return true;
do {
if(isalnum(*s) || *s == '.' || *s == ',' || *s == '-' || *s == ':' || *s == '/' || *s == '_')
if(isalnum((uint8_t)*s) || *s == '.' || *s == ',' || *s == '-' || *s == ':' || *s == '/' || *s == '_')
;
else
return false;
@ -393,7 +393,7 @@ int api_v2_claim(struct web_client *w, char *url) {
appconfig_set_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", CONFIG_BOOLEAN_AUTO);
appconfig_set(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", base_url);
uuid_t claimed_id;
nd_uuid_t claimed_id;
uuid_generate_random(claimed_id);
char claimed_id_str[UUID_STR_LEN];
uuid_unparse_lower(claimed_id, claimed_id_str);

View file

@ -286,6 +286,7 @@
#define NETDATA_CHART_PRIO_IPV4_BCAST_PACKETS 5105
#define NETDATA_CHART_PRIO_IPV4_MCAST 5150
#define NETDATA_CHART_PRIO_IPV4_MCAST_PACKETS 5155
#define NETDATA_CHART_PRIO_IPV4_TCP_PACKETS 5170
#define NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS 5180
#define NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS_MEM 5185
#define NETDATA_CHART_PRIO_IPV4_ICMP_PACKETS 5200
@ -311,7 +312,9 @@
#define NETDATA_CHART_PRIO_IPV6_BCAST 6050
#define NETDATA_CHART_PRIO_IPV6_MCAST 6100
#define NETDATA_CHART_PRIO_IPV6_MCAST_PACKETS 6105
#define NETDATA_CHART_PRIO_IPV6_TCP_PACKETS 6130
#define NETDATA_CHART_PRIO_IPV6_TCP_SOCKETS 6140
#define NETDATA_CHART_PRIO_IPV6_ICMP_PACKETS 6145
#define NETDATA_CHART_PRIO_IPV6_ICMP 6150
#define NETDATA_CHART_PRIO_IPV6_ICMP_REDIR 6155
#define NETDATA_CHART_PRIO_IPV6_ICMP_ERRORS 6160

View file

@ -552,7 +552,7 @@ static void normalize_utilization(struct target *root) {
// here we try to eliminate them by disabling childs processing either for specific dimensions
// or entirely. Of course, either way, we disable it just a single iteration.
kernel_uint_t max_time = get_system_cpus() * time_factor * RATES_DETAIL;
kernel_uint_t max_time = os_get_system_cpus() * time_factor * RATES_DETAIL;
kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
if(global_utime > max_time) global_utime = max_time;
@ -1013,7 +1013,7 @@ int main(int argc, char **argv) {
procfile_adaptive_initial_allocation = 1;
get_system_HZ();
os_get_system_HZ();
#if defined(__FreeBSD__)
time_factor = 1000000ULL / RATES_DETAIL; // FreeBSD uses usecs
#endif
@ -1025,8 +1025,8 @@ int main(int argc, char **argv) {
time_factor = system_hz; // Linux uses clock ticks
#endif
get_system_pid_max();
get_system_cpus_uncached();
os_get_system_pid_max();
os_get_system_cpus_uncached();
parse_args(argc, argv);

View file

@ -1261,7 +1261,7 @@ static inline void discovery_find_all_cgroups() {
discovery_find_all_cgroups_v2();
}
for (struct cgroup *cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
for (struct cgroup *cg = discovered_cgroup_root; cg && service_running(SERVICE_COLLECTORS); cg = cg->discovered_next) {
worker_is_busy(WORKER_DISCOVERY_PROCESS);
discovery_process_cgroup(cg);
}
@ -1289,6 +1289,7 @@ static inline void discovery_find_all_cgroups() {
void cgroup_discovery_worker(void *ptr)
{
UNUSED(ptr);
uv_thread_set_name_np("P[cgroupsdisc]");
worker_register("CGROUPSDISC");
worker_register_job_name(WORKER_DISCOVERY_INIT, "init");

View file

@ -3,12 +3,6 @@
#include "libnetdata/libnetdata.h"
#include "libnetdata/required_dummies.h"
#ifdef HAVE_SETNS
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* See feature_test_macros(7) */
#endif
#endif
char env_netdata_host_prefix[FILENAME_MAX + 50] = "";
char env_netdata_log_method[FILENAME_MAX + 50] = "";
char env_netdata_log_format[FILENAME_MAX + 50] = "";

View file

@ -1158,7 +1158,7 @@ static inline void update_cpu_limits(char **filename, unsigned long long *value,
int ret = -1;
if(value == &cg->cpuset_cpus) {
unsigned long ncpus = read_cpuset_cpus(*filename, get_system_cpus());
unsigned long ncpus = os_read_cpuset_cpus(*filename, os_get_system_cpus());
if(ncpus) {
*value = ncpus;
ret = 0;
@ -1199,7 +1199,7 @@ static inline void update_cpu_limits2(struct cgroup *cg) {
}
cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1), NULL);
cg->cpuset_cpus = get_system_cpus();
cg->cpuset_cpus = os_get_system_cpus();
char *s = "max\n\0";
if(strcmp(s, procfile_lineword(ff, 0, 0)) == 0){
@ -1513,13 +1513,14 @@ void update_cgroup_charts() {
// ----------------------------------------------------------------------------
// cgroups main
static void cgroup_main_cleanup(void *ptr) {
worker_unregister();
static void cgroup_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
worker_unregister();
usec_t max = 2 * USEC_PER_SEC, step = 50000;
@ -1554,13 +1555,13 @@ void cgroup_read_host_total_ram() {
}
void *cgroups_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(cgroup_main_cleanup) cleanup_ptr = ptr;
worker_register("CGROUPS");
worker_register_job_name(WORKER_CGROUPS_LOCK, "lock");
worker_register_job_name(WORKER_CGROUPS_READ, "read");
worker_register_job_name(WORKER_CGROUPS_CHART, "chart");
netdata_thread_cleanup_push(cgroup_main_cleanup, ptr);
if (getenv("KUBERNETES_SERVICE_HOST") != NULL && getenv("KUBERNETES_SERVICE_PORT") != NULL) {
is_inside_k8s = 1;
cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_YES;
@ -1592,8 +1593,6 @@ void *cgroups_main(void *ptr) {
goto exit;
}
uv_thread_set_name_np(discovery_thread.thread, "P[cgroups]");
// we register this only on localhost
// for the other nodes, the origin server should register it
cgroup_netdev_link_init();
@ -1613,12 +1612,11 @@ void *cgroups_main(void *ptr) {
usec_t step = cgroup_update_every * USEC_PER_SEC;
usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0;
netdata_thread_disable_cancelability();
while(service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
if (unlikely(!service_running(SERVICE_COLLECTORS)))
break;
@ -1658,6 +1656,5 @@ void *cgroups_main(void *ptr) {
}
exit:
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_COMMON_CONTEXTS_H
#define NETDATA_COMMON_CONTEXTS_H
#include "../../libnetdata/libnetdata.h"
#include "../../database/rrd.h"
#ifndef _COMMON_PLUGIN_NAME
#error You need to set _COMMON_PLUGIN_NAME before including common-contexts.h
#endif
#ifndef _COMMON_PLUGIN_MODULE_NAME
#error You need to set _COMMON_PLUGIN_MODULE_NAME before including common-contexts.h
#endif
#define _COMMON_CONFIG_SECTION "plugin:" _COMMON_PLUGIN_NAME ":" _COMMON_PLUGIN_MODULE_NAME
typedef void (*instance_labels_cb_t)(RRDSET *st, void *data);
#include "system.io.h"
#include "system.ram.h"
#include "mem.swap.h"
#include "mem.pgfaults.h"
#include "mem.available.h"
#include "disk.io.h"
#endif //NETDATA_COMMON_CONTEXTS_H

View file

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_DISK_IO_H
#define NETDATA_DISK_IO_H
#include "common-contexts.h"
typedef struct {
RRDSET *st_io;
RRDDIM *rd_io_reads;
RRDDIM *rd_io_writes;
} ND_DISK_IO;
static inline void common_disk_io(ND_DISK_IO *d, const char *id, const char *name, uint64_t bytes_read, uint64_t bytes_write, int update_every, instance_labels_cb_t cb, void *data) {
if(unlikely(!d->st_io)) {
d->st_io = rrdset_create_localhost(
"disk"
, id
, name
, "io"
, "disk.io"
, "Disk I/O Bandwidth"
, "KiB/s"
, _COMMON_PLUGIN_NAME
, _COMMON_PLUGIN_MODULE_NAME
, NETDATA_CHART_PRIO_DISK_IO
, update_every
, RRDSET_TYPE_AREA
);
d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
if(cb)
cb(d->st_io, data);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(d->st_io, d->rd_io_reads, (collected_number)bytes_read);
rrddim_set_by_pointer(d->st_io, d->rd_io_writes, (collected_number)bytes_write);
rrdset_done(d->st_io);
}
#endif //NETDATA_DISK_IO_H

View file

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_MEM_AVAILABLE_H
#define NETDATA_MEM_AVAILABLE_H
#include "common-contexts.h"
static inline void common_mem_available(uint64_t available_bytes, int update_every) {
static RRDSET *st_mem_available = NULL;
static RRDDIM *rd_avail = NULL;
if(unlikely(!st_mem_available)) {
st_mem_available = rrdset_create_localhost(
"mem"
, "available"
, NULL
, "overview"
, NULL
, "Available RAM for applications"
, "MiB"
, _COMMON_PLUGIN_NAME
, _COMMON_PLUGIN_MODULE_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE
, update_every
, RRDSET_TYPE_AREA
);
rd_avail = rrddim_add(st_mem_available, "avail", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_mem_available, rd_avail, (collected_number)available_bytes);
rrdset_done(st_mem_available);
}
#endif //NETDATA_MEM_AVAILABLE_H

View file

@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_MEM_PGFAULTS_H
#define NETDATA_MEM_PGFAULTS_H
#include "common-contexts.h"
static inline void common_mem_pgfaults(uint64_t minor, uint64_t major, int update_every) {
static RRDSET *st_pgfaults = NULL;
static RRDDIM *rd_minor = NULL, *rd_major = NULL;
if(unlikely(!st_pgfaults)) {
st_pgfaults = rrdset_create_localhost(
"mem"
, "pgfaults"
, NULL
, "page faults"
, NULL
, "Memory Page Faults"
, "faults/s"
, _COMMON_PLUGIN_NAME
, _COMMON_PLUGIN_MODULE_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_pgfaults, rd_minor, minor);
rrddim_set_by_pointer(st_pgfaults, rd_major, major);
rrdset_done(st_pgfaults);
}
#endif //NETDATA_MEM_PGFAULTS_H

View file

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common-contexts.h"
static inline void common_mem_swap(uint64_t free_bytes, uint64_t used_bytes, int update_every) {
static RRDSET *st_system_swap = NULL;
static RRDDIM *rd_free = NULL, *rd_used = NULL;
if(unlikely(!st_system_swap)) {
st_system_swap = rrdset_create_localhost(
"mem"
, "swap"
, NULL
, "swap"
, NULL
, "System Swap"
, "MiB"
, _COMMON_PLUGIN_NAME
, _COMMON_PLUGIN_MODULE_NAME
, NETDATA_CHART_PRIO_MEM_SWAP
, update_every
, RRDSET_TYPE_STACKED
);
rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL);
rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_system_swap, rd_used, (collected_number)used_bytes);
rrddim_set_by_pointer(st_system_swap, rd_free, (collected_number)free_bytes);
rrdset_done(st_system_swap);
}

View file

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_SYSTEM_IO_H
#define NETDATA_SYSTEM_IO_H
#include "common-contexts.h"
static inline void common_system_io(uint64_t read_bytes, uint64_t write_bytes, int update_every) {
static RRDSET *st_io = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
if(unlikely(!st_io)) {
st_io = rrdset_create_localhost(
"system"
, "io"
, NULL
, "disk"
, NULL
, "Disk I/O"
, "KiB/s"
, _COMMON_PLUGIN_NAME
, _COMMON_PLUGIN_MODULE_NAME
, NETDATA_CHART_PRIO_SYSTEM_IO
, update_every
, RRDSET_TYPE_AREA
);
rd_in = rrddim_add(st_io, "in", "reads", 1, 1024, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_io, "out", "writes", -1, 1024, RRD_ALGORITHM_INCREMENTAL);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_io, rd_in, (collected_number)read_bytes);
rrddim_set_by_pointer(st_io, rd_out, (collected_number)write_bytes);
rrdset_done(st_io);
}
#endif //NETDATA_SYSTEM_IO_H

View file

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_SYSTEM_RAM_H
#define NETDATA_SYSTEM_RAM_H
#include "common-contexts.h"
#define _system_ram_chart() \
rrdset_create_localhost( \
"system" \
, "ram" \
, NULL \
, "ram" \
, NULL \
, "System RAM" \
, "MiB" \
, _COMMON_PLUGIN_NAME \
, _COMMON_PLUGIN_MODULE_NAME \
, NETDATA_CHART_PRIO_SYSTEM_RAM \
, update_every \
, RRDSET_TYPE_STACKED \
)
#if defined(COMPILED_FOR_WINDOWS)
static inline void common_system_ram(uint64_t free_bytes, uint64_t used_bytes, int update_every) {
static RRDSET *st_system_ram = NULL;
static RRDDIM *rd_free = NULL;
static RRDDIM *rd_used = NULL;
if(unlikely(!st_system_ram)) {
st_system_ram = _system_ram_chart();
rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_system_ram, rd_free, (collected_number)free_bytes);
rrddim_set_by_pointer(st_system_ram, rd_used, (collected_number)used_bytes);
rrdset_done(st_system_ram);
}
#endif
#if defined(COMPILED_FOR_LINUX)
static inline void common_system_ram(uint64_t free_bytes, uint64_t used_bytes, uint64_t cached_bytes, uint64_t buffers_bytes, int update_every) {
static RRDSET *st_system_ram = NULL;
static RRDDIM *rd_free = NULL;
static RRDDIM *rd_used = NULL;
static RRDDIM *rd_cached = NULL;
static RRDDIM *rd_buffers = NULL;
if(unlikely(!st_system_ram)) {
st_system_ram = _system_ram_chart();
rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
}
// this always have to be in base units, so that exporting sends base units to other time-series db
rrddim_set_by_pointer(st_system_ram, rd_free, (collected_number)free_bytes);
rrddim_set_by_pointer(st_system_ram, rd_used, (collected_number)used_bytes);
rrddim_set_by_pointer(st_system_ram, rd_cached, (collected_number)cached_bytes);
rrddim_set_by_pointer(st_system_ram, rd_buffers, (collected_number)buffers_bytes);
rrdset_done(st_system_ram);
}
#endif
#endif //NETDATA_SYSTEM_RAM_H

View file

@ -14,7 +14,7 @@
#define MAX_STAT_USEC 10000LU
#define SLOW_UPDATE_EVERY 5
static netdata_thread_t *diskspace_slow_thread = NULL;
static ND_THREAD *diskspace_slow_thread = NULL;
static struct mountinfo *disk_mountinfo_root = NULL;
static int check_for_new_mountpoints_every = 15;
@ -513,9 +513,9 @@ cleanup:
dictionary_acquired_item_release(dict_mountpoints, item);
}
static void diskspace_slow_worker_cleanup(void *ptr)
{
UNUSED(ptr);
static void diskspace_slow_worker_cleanup(void *pptr) {
struct slow_worker_data *data = CLEANUP_FUNCTION_GET_PTR(pptr);
if(data) return;
collector_info("cleaning up...");
@ -526,14 +526,14 @@ static void diskspace_slow_worker_cleanup(void *ptr)
#define WORKER_JOB_SLOW_CLEANUP 1
struct slow_worker_data {
netdata_thread_t *slow_thread;
int update_every;
};
void *diskspace_slow_worker(void *ptr)
{
struct slow_worker_data *data = (struct slow_worker_data *)ptr;
CLEANUP_FUNCTION_REGISTER(diskspace_slow_worker_cleanup) cleanup_ptr = data;
worker_register("DISKSPACE_SLOW");
worker_register_job_name(WORKER_JOB_SLOW_MOUNTPOINT, "mountpoint");
worker_register_job_name(WORKER_JOB_SLOW_CLEANUP, "cleanup");
@ -542,8 +542,6 @@ void *diskspace_slow_worker(void *ptr)
int slow_update_every = data->update_every > SLOW_UPDATE_EVERY ? data->update_every : SLOW_UPDATE_EVERY;
netdata_thread_cleanup_push(diskspace_slow_worker_cleanup, data->slow_thread);
usec_t step = slow_update_every * USEC_PER_SEC;
usec_t real_step = USEC_PER_SEC;
heartbeat_t hb;
@ -600,26 +598,24 @@ void *diskspace_slow_worker(void *ptr)
}
}
netdata_thread_cleanup_pop(1);
free_basic_mountinfo_list(slow_mountinfo_root);
return NULL;
}
static void diskspace_main_cleanup(void *ptr) {
rrd_collector_finished();
worker_unregister();
static void diskspace_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
if (diskspace_slow_thread) {
netdata_thread_join(*diskspace_slow_thread, NULL);
freez(diskspace_slow_thread);
}
rrd_collector_finished();
worker_unregister();
if (diskspace_slow_thread)
nd_thread_join(diskspace_slow_thread);
free_basic_mountinfo_list(slow_mountinfo_tmp_root);
@ -846,6 +842,8 @@ int diskspace_function_mount_points(BUFFER *wb, const char *function __maybe_unu
}
void *diskspace_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(diskspace_main_cleanup) cleanup_ptr = ptr;
worker_register("DISKSPACE");
worker_register_job_name(WORKER_JOB_MOUNTINFO, "mountinfo");
worker_register_job_name(WORKER_JOB_MOUNTPOINT, "mountpoint");
@ -856,8 +854,6 @@ void *diskspace_main(void *ptr) {
"top", HTTP_ACCESS_ANONYMOUS_DATA,
diskspace_function_mount_points);
netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);
cleanup_mount_points = config_get_boolean(CONFIG_SECTION_DISKSPACE, "remove charts of unmounted disks" , cleanup_mount_points);
int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every);
@ -870,12 +866,9 @@ void *diskspace_main(void *ptr) {
netdata_mutex_init(&slow_mountinfo_mutex);
diskspace_slow_thread = mallocz(sizeof(netdata_thread_t));
struct slow_worker_data slow_worker_data = { .update_every = update_every };
struct slow_worker_data slow_worker_data = {.slow_thread = diskspace_slow_thread, .update_every = update_every};
netdata_thread_create(
diskspace_slow_thread,
diskspace_slow_thread = nd_thread_create(
"P[diskspace slow]",
NETDATA_THREAD_OPTION_JOINABLE,
diskspace_slow_worker,
@ -926,8 +919,5 @@ void *diskspace_main(void *ptr) {
mount_points_cleanup(false);
}
}
worker_unregister();
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -927,7 +927,7 @@ void ebpf_stop_threads(int sig)
// Child thread should be closed by itself.
pthread_mutex_lock(&ebpf_exit_cleanup);
if (main_thread_id != gettid() || only_one) {
if (main_thread_id != gettid_cached() || only_one) {
pthread_mutex_unlock(&ebpf_exit_cleanup);
return;
}
@ -935,7 +935,7 @@ void ebpf_stop_threads(int sig)
int i;
for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
if (ebpf_modules[i].enabled < NETDATA_THREAD_EBPF_STOPPING) {
netdata_thread_cancel(*ebpf_modules[i].thread->thread);
nd_thread_signal_cancel(ebpf_modules[i].thread->thread);
#ifdef NETDATA_DEV_MODE
netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].info.thread_name);
#endif
@ -945,13 +945,13 @@ void ebpf_stop_threads(int sig)
for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
if (ebpf_threads[i].thread)
netdata_thread_join(*ebpf_threads[i].thread, NULL);
nd_thread_join(ebpf_threads[i].thread);
}
ebpf_plugin_exit = true;
pthread_mutex_lock(&mutex_cgroup_shm);
netdata_thread_cancel(*cgroup_integration_thread.thread);
nd_thread_signal_cancel(cgroup_integration_thread.thread);
#ifdef NETDATA_DEV_MODE
netdata_log_info("Sending cancel for thread %s", cgroup_integration_thread.name);
#endif
@ -3040,7 +3040,7 @@ void set_global_variables()
}
isrh = get_redhat_release();
pid_max = get_system_pid_max();
pid_max = os_get_system_pid_max();
running_on_kernel = ebpf_get_kernel_version();
}
@ -3974,7 +3974,7 @@ int main(int argc, char **argv)
clocks_init();
nd_log_initialize_for_external_plugins(NETDATA_EBPF_PLUGIN_NAME);
main_thread_id = gettid();
main_thread_id = gettid_cached();
set_global_variables();
ebpf_parse_args(argc, argv);
@ -4010,11 +4010,13 @@ int main(int argc, char **argv)
ebpf_set_static_routine();
cgroup_integration_thread.thread = mallocz(sizeof(netdata_thread_t));
cgroup_integration_thread.start_routine = ebpf_cgroup_integration;
netdata_thread_create(cgroup_integration_thread.thread, cgroup_integration_thread.name,
NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
cgroup_integration_thread.thread = nd_thread_create(
cgroup_integration_thread.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_cgroup_integration,
NULL);
int i;
for (i = 0; ebpf_threads[i].name != NULL; i++) {
@ -4024,10 +4026,9 @@ int main(int argc, char **argv)
em->thread = st;
em->thread_id = i;
if (em->enabled != NETDATA_THREAD_EBPF_NOT_RUNNING) {
st->thread = mallocz(sizeof(netdata_thread_t));
em->enabled = NETDATA_THREAD_EBPF_RUNNING;
em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
} else {
em->lifetime = EBPF_DEFAULT_LIFETIME;
}
@ -4041,7 +4042,7 @@ int main(int argc, char **argv)
int update_apps_list = update_apps_every - 1;
int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
//Plugin will be killed when it receives a signal
for ( ; !ebpf_plugin_exit; global_iterations_counter++) {
for ( ; !ebpf_plugin_stop(); global_iterations_counter++) {
(void)heartbeat_next(&hb, step);
if (global_iterations_counter % EBPF_DEFAULT_UPDATE_EVERY == 0) {

View file

@ -389,6 +389,11 @@ void ebpf_read_local_addresses_unsafe();
extern ebpf_filesystem_partitions_t localfs[];
extern ebpf_sync_syscalls_t local_syscalls[];
extern bool ebpf_plugin_exit;
static inline bool ebpf_plugin_stop(void) {
return ebpf_plugin_exit || nd_thread_signaled_to_cancel();
}
void ebpf_stop_threads(int sig);
extern netdata_ebpf_judy_pid_t ebpf_judy_pid;

View file

@ -523,12 +523,13 @@ void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
*
* @param ptr thread data.
*/
static void ebpf_cachestat_exit(void *ptr)
static void ebpf_cachestat_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_cachestat.thread)
netdata_thread_cancel(*ebpf_read_cachestat.thread);
nd_thread_signal_cancel(ebpf_read_cachestat.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -840,13 +841,11 @@ void *ebpf_read_cachestat_thread(void *ptr)
uint32_t lifetime = em->lifetime;
uint32_t running_time = 0;
usec_t period = update_every * USEC_PER_SEC;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_read_cachestat_apps_table(maps_per_core, max_period);
ebpf_resume_apps_data();
@ -862,7 +861,6 @@ void *ebpf_read_cachestat_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -1402,10 +1400,10 @@ static void cachestat_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -1593,9 +1591,10 @@ static int ebpf_cachestat_load_bpf(ebpf_module_t *em)
*/
void *ebpf_cachestat_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_cachestat_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_cachestat_exit) cleanup_ptr = em;
em->maps = cachestat_maps;
ebpf_update_pid_table(&cachestat_maps[NETDATA_CACHESTAT_PID_STATS], em);
@ -1628,18 +1627,16 @@ void *ebpf_cachestat_thread(void *ptr)
pthread_mutex_unlock(&lock);
ebpf_read_cachestat.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_cachestat.thread,
ebpf_read_cachestat.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_cachestat_thread,
em);
ebpf_read_cachestat.thread = nd_thread_create(
ebpf_read_cachestat.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_cachestat_thread,
em);
cachestat_collector(em);
endcachestat:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -348,18 +348,6 @@ void ebpf_create_charts_on_systemd(ebpf_systemd_args_t *chart)
// --------------------------------------------------------------------------------------------------------------------
// Cgroup main thread
/**
* CGROUP exit
*
* Clean up the main thread.
*
* @param ptr thread data.
*/
static void ebpf_cgroup_exit(void *ptr)
{
UNUSED(ptr);
}
/**
* Cgroup integratin
*
@ -369,16 +357,14 @@ static void ebpf_cgroup_exit(void *ptr)
*
* @return It always returns NULL.
*/
void *ebpf_cgroup_integration(void *ptr)
void *ebpf_cgroup_integration(void *ptr __maybe_unused)
{
netdata_thread_cleanup_push(ebpf_cgroup_exit, ptr);
usec_t step = USEC_PER_SEC;
int counter = NETDATA_EBPF_CGROUP_UPDATE - 1;
heartbeat_t hb;
heartbeat_init(&hb);
//Plugin will be killed when it receives a signal
while (!ebpf_plugin_exit) {
while (!ebpf_plugin_stop()) {
(void)heartbeat_next(&hb, step);
// We are using a small heartbeat time to wake up thread,
@ -392,6 +378,5 @@ void *ebpf_cgroup_integration(void *ptr)
}
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -451,12 +451,13 @@ static void ebpf_obsolete_dc_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_dcstat_exit(void *ptr)
static void ebpf_dcstat_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_dcstat.thread)
netdata_thread_cancel(*ebpf_read_dcstat.thread);
nd_thread_signal_cancel(ebpf_read_dcstat.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -641,13 +642,11 @@ void *ebpf_read_dcstat_thread(void *ptr)
uint32_t running_time = 0;
usec_t period = update_every * USEC_PER_SEC;
int max_period = update_every * EBPF_CLEANUP_FACTOR;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_read_dc_apps_table(maps_per_core, max_period);
ebpf_dc_resume_apps_data();
@ -663,7 +662,6 @@ void *ebpf_read_dcstat_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -1261,10 +1259,10 @@ static void dcstat_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -1403,9 +1401,9 @@ static int ebpf_dcstat_load_bpf(ebpf_module_t *em)
*/
void *ebpf_dcstat_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_dcstat_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_dcstat_exit) cleanup_ptr = em;
em->maps = dcstat_maps;
ebpf_update_pid_table(&dcstat_maps[NETDATA_DCSTAT_PID_STATS], em);
@ -1437,18 +1435,13 @@ void *ebpf_dcstat_thread(void *ptr)
pthread_mutex_unlock(&lock);
ebpf_read_dcstat.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_dcstat.thread,
ebpf_read_dcstat.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_dcstat_thread,
em);
ebpf_read_dcstat.thread = nd_thread_create(ebpf_read_dcstat.name, NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_dcstat_thread, em);
dcstat_collector(em);
enddcstat:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -506,9 +506,10 @@ static void ebpf_obsolete_disk_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_disk_exit(void *ptr)
static void ebpf_disk_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -779,10 +780,10 @@ static void disk_collector(ebpf_module_t *em)
int maps_per_core = em->maps_per_core;
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -890,9 +891,10 @@ static int ebpf_disk_load_bpf(ebpf_module_t *em)
*/
void *ebpf_disk_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_disk_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_disk_exit) cleanup_ptr = em;
em->maps = disk_maps;
if (ebpf_disk_enable_tracepoints()) {
@ -934,7 +936,5 @@ void *ebpf_disk_thread(void *ptr)
enddisk:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -546,12 +546,13 @@ static void ebpf_obsolete_fd_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_fd_exit(void *ptr)
static void ebpf_fd_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_fd.thread)
netdata_thread_cancel(*ebpf_read_fd.thread);
nd_thread_signal_cancel(ebpf_read_fd.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -773,13 +774,11 @@ void *ebpf_read_fd_thread(void *ptr)
uint32_t running_time = 0;
usec_t period = update_every * USEC_PER_SEC;
int max_period = update_every * EBPF_CLEANUP_FACTOR;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_read_fd_apps_table(maps_per_core, max_period);
ebpf_fd_resume_apps_data();
@ -795,7 +794,6 @@ void *ebpf_read_fd_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -1205,10 +1203,10 @@ static void fd_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -1439,9 +1437,10 @@ static int ebpf_fd_load_bpf(ebpf_module_t *em)
*/
void *ebpf_fd_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_fd_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_fd_exit) cleanup_ptr = em;
em->maps = fd_maps;
#ifdef LIBBPF_MAJOR_VERSION
@ -1467,18 +1466,12 @@ void *ebpf_fd_thread(void *ptr)
pthread_mutex_unlock(&lock);
ebpf_read_fd.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_fd.thread,
ebpf_read_fd.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_fd_thread,
em);
ebpf_read_fd.thread = nd_thread_create(ebpf_read_fd.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_fd_thread, em);
fd_collector(em);
endfd:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -724,9 +724,10 @@ static void ebpf_obsolete_filesystem_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_filesystem_exit(void *ptr)
static void ebpf_filesystem_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -915,10 +916,10 @@ static void filesystem_collector(ebpf_module_t *em)
int counter = update_every - 1;
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -990,9 +991,10 @@ static void ebpf_set_maps()
*/
void *ebpf_filesystem_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_filesystem_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_filesystem_exit) cleanup_ptr = em;
ebpf_set_maps();
ebpf_update_filesystem();
@ -1024,6 +1026,5 @@ void *ebpf_filesystem_thread(void *ptr)
endfilesystem:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -20,13 +20,10 @@ static int ebpf_function_start_thread(ebpf_module_t *em, int period)
{
struct netdata_static_thread *st = em->thread;
// another request for thread that already ran, cleanup and restart
if (st->thread)
freez(st->thread);
if (period <= 0)
period = EBPF_DEFAULT_LIFETIME;
st->thread = mallocz(sizeof(netdata_thread_t));
st->thread = NULL;
em->enabled = NETDATA_THREAD_EBPF_FUNCTION_RUNNING;
em->lifetime = period;
@ -34,7 +31,8 @@ static int ebpf_function_start_thread(ebpf_module_t *em, int period)
netdata_log_info("Starting thread %s with lifetime = %d", em->info.thread_name, period);
#endif
return netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
return st->thread ? 0 : 1;
}
/*****************************************************************
@ -714,10 +712,10 @@ void *ebpf_function_thread(void *ptr)
heartbeat_t hb;
heartbeat_init(&hb);
while(!ebpf_plugin_exit) {
while(!ebpf_plugin_stop()) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit) {
if (ebpf_plugin_stop()) {
break;
}
}

View file

@ -244,9 +244,10 @@ static void ebpf_obsolete_hardirq_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void hardirq_exit(void *ptr)
static void hardirq_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -581,10 +582,10 @@ static void hardirq_collector(ebpf_module_t *em)
//This will be cancelled by its parent
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -658,9 +659,10 @@ static int ebpf_hardirq_load_bpf(ebpf_module_t *em)
*/
void *ebpf_hardirq_thread(void *ptr)
{
netdata_thread_cleanup_push(hardirq_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(hardirq_exit) cleanup_ptr = em;
em->maps = hardirq_maps;
if (ebpf_enable_tracepoints(hardirq_tracepoints) == 0) {
@ -680,7 +682,5 @@ void *ebpf_hardirq_thread(void *ptr)
endhardirq:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -157,9 +157,10 @@ static void ebpf_obsolete_mdflush_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void mdflush_exit(void *ptr)
static void mdflush_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -346,10 +347,10 @@ static void mdflush_collector(ebpf_module_t *em)
int maps_per_core = em->maps_per_core;
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -424,9 +425,9 @@ static int ebpf_mdflush_load_bpf(ebpf_module_t *em)
*/
void *ebpf_mdflush_thread(void *ptr)
{
netdata_thread_cleanup_push(mdflush_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(mdflush_exit) cleanup_ptr = em;
em->maps = mdflush_maps;
char *md_flush_request = ebpf_find_symbol("md_flush_request");
@ -450,7 +451,5 @@ endmdflush:
freez(md_flush_request);
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -261,9 +261,10 @@ static void ebpf_obsolete_mount_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_mount_exit(void *ptr)
static void ebpf_mount_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -369,9 +370,9 @@ static void mount_collector(ebpf_module_t *em)
int maps_per_core = em->maps_per_core;
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -484,9 +485,9 @@ static int ebpf_mount_load_bpf(ebpf_module_t *em)
*/
void *ebpf_mount_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_mount_exit, ptr);
ebpf_module_t *em = ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_mount_exit) cleanup_ptr = em;
ebpf_module_t *em = (ebpf_module_t *)ptr;
em->maps = mount_maps;
#ifdef LIBBPF_MAJOR_VERSION
@ -512,6 +513,5 @@ void *ebpf_mount_thread(void *ptr)
endmount:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -128,9 +128,10 @@ static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void oomkill_cleanup(void *ptr)
static void oomkill_cleanup(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -457,9 +458,9 @@ static void oomkill_collector(ebpf_module_t *em)
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -532,9 +533,10 @@ void ebpf_oomkill_create_apps_charts(struct ebpf_module *em, void *ptr)
*/
void *ebpf_oomkill_thread(void *ptr)
{
netdata_thread_cleanup_push(oomkill_cleanup, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(oomkill_cleanup) cleanup_ptr = em;
em->maps = oomkill_maps;
#define NETDATA_DEFAULT_OOM_DISABLED_MSG "Disabling OOMKILL thread, because"
@ -578,7 +580,5 @@ void *ebpf_oomkill_thread(void *ptr)
endoomkill:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -689,9 +689,10 @@ static void ebpf_process_disable_tracepoints()
*
* @param ptr thread data.
*/
static void ebpf_process_exit(void *ptr)
static void ebpf_process_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -1135,10 +1136,10 @@ static void process_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
usec_t dt = heartbeat_next(&hb, USEC_PER_SEC);
(void)dt;
if (ebpf_plugin_exit)
if (ebpf_plugin_stop())
break;
if (++counter == update_every) {
@ -1279,9 +1280,10 @@ static int ebpf_process_enable_tracepoints()
*/
void *ebpf_process_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_process_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_process_exit) cleanup_ptr = em;
em->maps = process_maps;
pthread_mutex_lock(&ebpf_exit_cleanup);
@ -1322,6 +1324,5 @@ void *ebpf_process_thread(void *ptr)
ebpf_update_disabled_plugin_stats(em);
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -448,12 +448,13 @@ static void ebpf_obsolete_shm_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_shm_exit(void *ptr)
static void ebpf_shm_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_shm.thread)
netdata_thread_cancel(*ebpf_read_shm.thread);
nd_thread_signal_cancel(ebpf_read_shm.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -1066,13 +1067,11 @@ void *ebpf_read_shm_thread(void *ptr)
uint32_t running_time = 0;
usec_t period = update_every * USEC_PER_SEC;
int max_period = update_every * EBPF_CLEANUP_FACTOR;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_read_shm_apps_table(maps_per_core, max_period);
ebpf_shm_resume_apps_data();
@ -1088,7 +1087,6 @@ void *ebpf_read_shm_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -1109,9 +1107,9 @@ static void shm_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -1327,9 +1325,10 @@ static int ebpf_shm_load_bpf(ebpf_module_t *em)
*/
void *ebpf_shm_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_shm_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_shm_exit) cleanup_ptr = em;
em->maps = shm_maps;
ebpf_update_pid_table(&shm_maps[NETDATA_PID_SHM_TABLE], em);
@ -1364,18 +1363,12 @@ void *ebpf_shm_thread(void *ptr)
ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
pthread_mutex_unlock(&lock);
ebpf_read_shm.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_shm.thread,
ebpf_read_shm.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_shm_thread,
em);
ebpf_read_shm.thread = nd_thread_create(ebpf_read_shm.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_shm_thread, em);
shm_collector(em);
endshm:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -881,12 +881,13 @@ static void ebpf_socket_obsolete_global_charts(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_socket_exit(void *ptr)
static void ebpf_socket_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_socket.thread)
netdata_thread_cancel(*ebpf_read_socket.thread);
nd_thread_signal_cancel(ebpf_read_socket.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -1678,7 +1679,6 @@ static void ebpf_socket_translate(netdata_socket_plus_t *dst, netdata_socket_idx
*/
static void ebpf_update_array_vectors(ebpf_module_t *em)
{
netdata_thread_disable_cancelability();
netdata_socket_idx_t key = {};
netdata_socket_idx_t next_key = {};
@ -1776,7 +1776,6 @@ end_socket_loop:
memset(values, 0, length);
memcpy(&key, &next_key, sizeof(key));
}
netdata_thread_enable_cancelability();
}
/**
* Resume apps data
@ -1838,9 +1837,9 @@ void *ebpf_read_socket_thread(void *ptr)
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
usec_t period = update_every * USEC_PER_SEC;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
pthread_mutex_lock(&collect_data_mutex);
@ -2653,9 +2652,9 @@ static void socket_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -2876,9 +2875,10 @@ static int ebpf_socket_load_bpf(ebpf_module_t *em)
*/
void *ebpf_socket_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_socket_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_socket_exit) cleanup_ptr = em;
if (em->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
collector_error("There is already a thread %s running", em->info.thread_name);
return NULL;
@ -2918,12 +2918,8 @@ void *ebpf_socket_thread(void *ptr)
socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
algorithms, NETDATA_MAX_SOCKET_VECTOR);
ebpf_read_socket.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_socket.thread,
ebpf_read_socket.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_socket_thread,
em);
ebpf_read_socket.thread = nd_thread_create(ebpf_read_socket.name, NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_socket_thread, em);
pthread_mutex_lock(&lock);
ebpf_socket_create_global_charts(em);
@ -2937,7 +2933,5 @@ void *ebpf_socket_thread(void *ptr)
endsocket:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -88,9 +88,10 @@ static void ebpf_obsolete_softirq_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void softirq_cleanup(void *ptr)
static void softirq_cleanup(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -219,9 +220,9 @@ static void softirq_collector(ebpf_module_t *em)
//This will be cancelled by its parent
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -258,9 +259,10 @@ static void softirq_collector(ebpf_module_t *em)
*/
void *ebpf_softirq_thread(void *ptr)
{
netdata_thread_cleanup_push(softirq_cleanup, ptr);
ebpf_module_t *em = ptr;
CLEANUP_FUNCTION_REGISTER(softirq_cleanup) cleanup_ptr = em;
ebpf_module_t *em = (ebpf_module_t *)ptr;
em->maps = softirq_maps;
if (ebpf_enable_tracepoints(softirq_tracepoints) == 0) {
@ -280,7 +282,5 @@ void *ebpf_softirq_thread(void *ptr)
endsoftirq:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -394,7 +394,7 @@ static void ebpf_swap_exit(void *ptr)
ebpf_module_t *em = (ebpf_module_t *)ptr;
if (ebpf_read_swap.thread)
netdata_thread_cancel(*ebpf_read_swap.thread);
nd_thread_signal_cancel(ebpf_read_swap.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -595,13 +595,11 @@ void *ebpf_read_swap_thread(void *ptr)
usec_t period = update_every * USEC_PER_SEC;
int max_period = update_every * EBPF_CLEANUP_FACTOR;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_read_swap_apps_table(maps_per_core, max_period);
ebpf_swap_resume_apps_data();
@ -617,7 +615,6 @@ void *ebpf_read_swap_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -920,9 +917,9 @@ static void swap_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -1131,9 +1128,10 @@ static int ebpf_swap_set_internal_value()
*/
void *ebpf_swap_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_swap_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_swap_exit) cleanup_ptr = em;
em->maps = swap_maps;
ebpf_update_pid_table(&swap_maps[NETDATA_PID_SWAP_TABLE], em);
@ -1161,18 +1159,13 @@ void *ebpf_swap_thread(void *ptr)
ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
pthread_mutex_unlock(&lock);
ebpf_read_swap.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_swap.thread,
ebpf_read_swap.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_swap_thread,
em);
ebpf_read_swap.thread = nd_thread_create(ebpf_read_swap.name, NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_swap_thread, em);
swap_collector(em);
endswap:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -351,9 +351,10 @@ static void ebpf_obsolete_sync_global(ebpf_module_t *em)
*
* @param ptr thread data.
*/
static void ebpf_sync_exit(void *ptr)
static void ebpf_sync_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -564,9 +565,9 @@ static void sync_collector(ebpf_module_t *em)
int maps_per_core = em->maps_per_core;
uint32_t running_time = 0;
uint32_t lifetime = em->lifetime;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -703,10 +704,10 @@ static void ebpf_set_sync_maps()
*/
void *ebpf_sync_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_sync_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_sync_exit) cleanup_ptr = em;
ebpf_set_sync_maps();
ebpf_sync_parse_syscalls();
@ -734,6 +735,5 @@ void *ebpf_sync_thread(void *ptr)
endsync:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -881,12 +881,13 @@ static void ebpf_obsolete_vfs_global(ebpf_module_t *em)
*
* @param ptr thread data.
**/
static void ebpf_vfs_exit(void *ptr)
static void ebpf_vfs_exit(void *pptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!em) return;
if (ebpf_read_vfs.thread)
netdata_thread_cancel(*ebpf_read_vfs.thread);
nd_thread_signal_cancel(ebpf_read_vfs.thread);
if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
pthread_mutex_lock(&lock);
@ -2049,13 +2050,11 @@ void *ebpf_read_vfs_thread(void *ptr)
uint32_t running_time = 0;
usec_t period = update_every * USEC_PER_SEC;
int max_period = update_every * EBPF_CLEANUP_FACTOR;
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, period);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
netdata_thread_disable_cancelability();
pthread_mutex_lock(&collect_data_mutex);
ebpf_vfs_read_apps(maps_per_core, max_period);
ebpf_vfs_resume_apps_data();
@ -2071,7 +2070,6 @@ void *ebpf_read_vfs_thread(void *ptr)
em->running_time = running_time;
pthread_mutex_unlock(&ebpf_exit_cleanup);
netdata_thread_enable_cancelability();
}
return NULL;
@ -2095,9 +2093,9 @@ static void vfs_collector(ebpf_module_t *em)
uint32_t lifetime = em->lifetime;
netdata_idx_t *stats = em->hash_table_stats;
memset(stats, 0, sizeof(em->hash_table_stats));
while (!ebpf_plugin_exit && running_time < lifetime) {
while (!ebpf_plugin_stop() && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_plugin_exit || ++counter != update_every)
if (ebpf_plugin_stop() || ++counter != update_every)
continue;
counter = 0;
@ -2606,9 +2604,10 @@ static int ebpf_vfs_load_bpf(ebpf_module_t *em)
*/
void *ebpf_vfs_thread(void *ptr)
{
netdata_thread_cleanup_push(ebpf_vfs_exit, ptr);
ebpf_module_t *em = (ebpf_module_t *)ptr;
CLEANUP_FUNCTION_REGISTER(ebpf_vfs_exit) cleanup_ptr = em;
em->maps = vfs_maps;
ebpf_update_pid_table(&vfs_maps[NETDATA_VFS_PID], em);
@ -2637,18 +2636,12 @@ void *ebpf_vfs_thread(void *ptr)
pthread_mutex_unlock(&lock);
ebpf_read_vfs.thread = mallocz(sizeof(netdata_thread_t));
netdata_thread_create(ebpf_read_vfs.thread,
ebpf_read_vfs.name,
NETDATA_THREAD_OPTION_DEFAULT,
ebpf_read_vfs_thread,
em);
ebpf_read_vfs.thread = nd_thread_create(ebpf_read_vfs.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_vfs_thread, em);
vfs_collector(em);
endvfs:
ebpf_update_disabled_plugin_stats(em);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -71,23 +71,24 @@ static struct freebsd_module {
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 33
#endif
static void freebsd_main_cleanup(void *ptr)
static void freebsd_main_cleanup(void *pptr)
{
worker_unregister();
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
worker_unregister();
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
}
void *freebsd_main(void *ptr)
{
worker_register("FREEBSD");
CLEANUP_FUNCTION_REGISTER(freebsd_main_cleanup) cleanup_ptr = ptr;
netdata_thread_cleanup_push(freebsd_main_cleanup, ptr);
worker_register("FREEBSD");
// initialize FreeBSD plugin
if (freebsd_plugin_init())
@ -131,6 +132,5 @@ void *freebsd_main(void *ptr)
}
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -1977,12 +1977,9 @@ int main (int argc, char **argv) {
},
};
netdata_thread_t sensors_thread = 0, sel_thread = 0;
netdata_thread_create(&sensors_thread, "IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
nd_thread_create("IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
if(netdata_do_sel)
netdata_thread_create(&sel_thread, "IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
nd_thread_create("IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
// ------------------------------------------------------------------------
// the main loop

View file

@ -4,23 +4,24 @@
#define CPU_IDLEJITTER_SLEEP_TIME_MS 20
static void cpuidlejitter_main_cleanup(void *ptr) {
worker_unregister();
static void cpuidlejitter_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!pptr) return;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
worker_unregister();
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
}
void *cpuidlejitter_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(cpuidlejitter_main_cleanup) cleanup_ptr = ptr;
worker_register("IDLEJITTER");
worker_register_job_name(0, "measurements");
netdata_thread_cleanup_push(cpuidlejitter_main_cleanup, ptr);
usec_t sleep_ut = config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS) * USEC_PER_MS;
if(sleep_ut <= 0) {
config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
@ -85,7 +86,6 @@ void *cpuidlejitter_main(void *ptr) {
}
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -48,7 +48,7 @@ static const char *yaml_event_name(yaml_event_type_t type) {
}
#define yaml_error(parser, event, fmt, args...) yaml_error_with_trace(parser, event, __LINE__, __FUNCTION__, __FILE__, fmt, ##args)
static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) __attribute__ ((format(__printf__, 6, 7)));
static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) PRINTFLIKE(6, 7);
static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) {
char buf[1024] = ""; // Initialize buf to an empty string
const char *type = "";

View file

@ -277,7 +277,7 @@ static inline void send_key_value_constant(LOG_JOB *jb __maybe_unused, HASHED_KE
// fprintf(stderr, "SET %s=%.*s\n", ht_key->key, (int)ht_key->value.len, ht_key->value.txt);
}
static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) __attribute__ ((format(__printf__, 3, 4)));
static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) PRINTFLIKE(3, 4);
static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) {
HASHED_KEY *ht_key = get_key_from_hashtable(jb, key);

View file

@ -17,11 +17,34 @@
#include <stdarg.h>
#include <assert.h>
// ----------------------------------------------------------------------------
// compatibility
#ifndef HAVE_STRNDUP
// strndup() is not available on Windows
static inline char *os_strndup( const char *s1, size_t n)
{
char *copy= (char*)malloc( n+1 );
memcpy( copy, s1, n );
copy[n] = 0;
return copy;
};
#define strndup(s, n) os_strndup(s, n)
#endif
#if defined(HAVE_FUNC_ATTRIBUTE_FORMAT) && !defined(COMPILED_FOR_MACOS)
#define PRINTFLIKE(f, a) __attribute__ ((format(gnu_printf, f, a)))
#elif defined(HAVE_FUNC_ATTRIBUTE_FORMAT)
#define PRINTFLIKE(f, a) __attribute__ ((format(printf, f, a)))
#else
#define PRINTFLIKE(f, a)
#endif
// ----------------------------------------------------------------------------
// logging
// enable the compiler to check for printf like errors on our log2stderr() function
static inline void log2stderr(const char *format, ...) __attribute__ ((format(__printf__, 1, 2)));
static inline void log2stderr(const char *format, ...) PRINTFLIKE(1, 2);
static inline void log2stderr(const char *format, ...) {
va_list args;
va_start(args, format);

View file

@ -25,23 +25,24 @@ static struct macos_module {
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 3
#endif
static void macos_main_cleanup(void *ptr)
static void macos_main_cleanup(void *pptr)
{
worker_unregister();
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
worker_unregister();
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
}
void *macos_main(void *ptr)
{
worker_register("MACOS");
CLEANUP_FUNCTION_REGISTER(macos_main_cleanup) cleanup_ptr = ptr;
netdata_thread_cleanup_push(macos_main_cleanup, ptr);
worker_register("MACOS");
// check the enabled status for each module
for (int i = 0; macos_modules[i].name; i++) {
@ -76,6 +77,5 @@ void *macos_main(void *ptr)
}
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -739,7 +739,7 @@ close_and_send:
int main(int argc __maybe_unused, char **argv __maybe_unused) {
clocks_init();
netdata_thread_set_tag("NETWORK-VIEWER");
nd_thread_tag_set("NETWORK-VIEWER");
nd_log_initialize_for_external_plugins("network-viewer.plugin");
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");

View file

@ -246,7 +246,7 @@ static int perf_init() {
struct perf_event *current_event = NULL;
unsigned long flags = 0;
number_of_cpus = (int)get_system_cpus();
number_of_cpus = (int)os_get_system_cpus();
// initialize all perf event file descriptors
for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {

View file

@ -332,8 +332,8 @@ int main(int argc, char *argv[]) {
return 3;
}
char new_path[] = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
setenv("PATH", new_path, 1);
char new_path[] = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
putenv(new_path);
bool found = false;
char filename[FILENAME_MAX];

View file

@ -6,6 +6,16 @@
char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { [0] = PLUGINS_DIR, };
struct plugind *pluginsd_root = NULL;
static inline void pluginsd_sleep(const int seconds) {
int timeout_ms = seconds * 1000;
int waited_ms = 0;
while(waited_ms < timeout_ms) {
if(!service_running(SERVICE_COLLECTORS)) break;
sleep_usec(ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS * USEC_PER_MS);
waited_ms += ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS;
}
}
inline size_t pluginsd_initialize_plugin_directories()
{
char plugins_dirs[(FILENAME_MAX * 2) + 1];
@ -47,8 +57,9 @@ static inline bool plugin_is_running(struct plugind *cd) {
return ret;
}
static void pluginsd_worker_thread_cleanup(void *arg) {
struct plugind *cd = (struct plugind *)arg;
static void pluginsd_worker_thread_cleanup(void *pptr) {
struct plugind *cd = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!cd) return;
worker_unregister();
@ -79,7 +90,7 @@ static void pluginsd_worker_thread_cleanup(void *arg) {
#define SERIAL_FAILURES_THRESHOLD 10
static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
if (likely(cd->successful_collections)) {
sleep((unsigned int)cd->update_every);
pluginsd_sleep(cd->update_every);
return;
}
@ -88,7 +99,7 @@ static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid,
plugin_is_enabled(cd) ? "Waiting a bit before starting it again." : "Will not start it again - it is now disabled.");
sleep((unsigned int)(cd->update_every * 10));
pluginsd_sleep(cd->update_every * 10);
return;
}
@ -121,7 +132,8 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
netdata_log_error("PLUGINSD: 'host:%s', '%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, worker_ret_code, cd->successful_collections,
plugin_is_enabled(cd) ? "Waiting a bit before starting it again." : "Will not start it again - it is disabled.");
sleep((unsigned int)(cd->update_every * 10));
pluginsd_sleep(cd->update_every * 10);
return;
}
@ -138,73 +150,73 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
#undef SERIAL_FAILURES_THRESHOLD
static void *pluginsd_worker_thread(void *arg) {
struct plugind *cd = (struct plugind *) arg;
CLEANUP_FUNCTION_REGISTER(pluginsd_worker_thread_cleanup) cleanup_ptr = cd;
worker_register("PLUGINSD");
netdata_thread_cleanup_push(pluginsd_worker_thread_cleanup, arg)
{
struct plugind *cd = (struct plugind *) arg;
plugin_set_running(cd);
plugin_set_running(cd);
size_t count = 0;
size_t count = 0;
while(service_running(SERVICE_COLLECTORS)) {
FILE *fp_child_input = NULL;
FILE *fp_child_output = netdata_popen(cd->cmd, &cd->unsafe.pid, &fp_child_input);
while(service_running(SERVICE_COLLECTORS)) {
FILE *fp_child_input = NULL;
FILE *fp_child_output = netdata_popen(cd->cmd, &cd->unsafe.pid, &fp_child_input);
if(unlikely(!fp_child_input || !fp_child_output)) {
netdata_log_error("PLUGINSD: 'host:%s', cannot popen(\"%s\", \"r\").",
rrdhost_hostname(cd->host), cd->cmd);
break;
}
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"PLUGINSD: 'host:%s' connected to '%s' running on pid %d",
rrdhost_hostname(cd->host),
cd->fullfilename, cd->unsafe.pid);
const char *plugin = strrchr(cd->fullfilename, '/');
if(plugin)
plugin++;
else
plugin = cd->fullfilename;
char module[100];
snprintfz(module, sizeof(module), "plugins.d[%s]", plugin);
ND_LOG_STACK lgs[] = {
ND_LOG_FIELD_TXT(NDF_MODULE, module),
ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rrdhost_hostname(cd->host)),
ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "pluginsd"),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
count = pluginsd_process(cd->host, cd, fp_child_input, fp_child_output, 0);
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"PLUGINSD: 'host:%s', '%s' (pid %d) disconnected after %zu successful data collections (ENDs).",
rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, count);
killpid(cd->unsafe.pid);
int worker_ret_code = netdata_pclose(fp_child_input, fp_child_output, cd->unsafe.pid);
if(likely(worker_ret_code == 0))
pluginsd_worker_thread_handle_success(cd);
else
pluginsd_worker_thread_handle_error(cd, worker_ret_code);
cd->unsafe.pid = 0;
if(unlikely(!plugin_is_enabled(cd)))
break;
if(unlikely(!fp_child_input || !fp_child_output)) {
netdata_log_error("PLUGINSD: 'host:%s', cannot popen(\"%s\", \"r\").",
rrdhost_hostname(cd->host), cd->cmd);
break;
}
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"PLUGINSD: 'host:%s' connected to '%s' running on pid %d",
rrdhost_hostname(cd->host),
cd->fullfilename, cd->unsafe.pid);
const char *plugin = strrchr(cd->fullfilename, '/');
if(plugin)
plugin++;
else
plugin = cd->fullfilename;
char module[100];
snprintfz(module, sizeof(module), "plugins.d[%s]", plugin);
ND_LOG_STACK lgs[] = {
ND_LOG_FIELD_TXT(NDF_MODULE, module),
ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rrdhost_hostname(cd->host)),
ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "pluginsd"),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
count = pluginsd_process(cd->host, cd, fp_child_input, fp_child_output, 0);
nd_log(NDLS_DAEMON, NDLP_DEBUG,
"PLUGINSD: 'host:%s', '%s' (pid %d) disconnected after %zu successful data collections (ENDs).",
rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, count);
killpid(cd->unsafe.pid);
int worker_ret_code = netdata_pclose(fp_child_input, fp_child_output, cd->unsafe.pid);
if(likely(worker_ret_code == 0))
pluginsd_worker_thread_handle_success(cd);
else
pluginsd_worker_thread_handle_error(cd, worker_ret_code);
cd->unsafe.pid = 0;
if(unlikely(!plugin_is_enabled(cd)))
break;
}
netdata_thread_cleanup_pop(1);
return NULL;
}
static void pluginsd_main_cleanup(void *data) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
static void pluginsd_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
netdata_log_info("PLUGINSD: cleaning up...");
@ -215,7 +227,7 @@ static void pluginsd_main_cleanup(void *data) {
netdata_log_info("PLUGINSD: 'host:%s', stopping plugin thread: %s",
rrdhost_hostname(cd->host), cd->id);
netdata_thread_cancel(cd->unsafe.thread);
nd_thread_signal_cancel(cd->unsafe.thread);
}
spinlock_unlock(&cd->unsafe.spinlock);
}
@ -226,9 +238,8 @@ static void pluginsd_main_cleanup(void *data) {
worker_unregister();
}
void *pluginsd_main(void *ptr)
{
netdata_thread_cleanup_push(pluginsd_main_cleanup, ptr);
void *pluginsd_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(pluginsd_main_cleanup) cleanup_ptr = ptr;
int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
int scan_frequency = (int)config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
@ -340,11 +351,8 @@ void *pluginsd_main(void *ptr)
snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PD[%s]", pluginname);
// spawn a new thread for it
netdata_thread_create(&cd->unsafe.thread,
tag,
NETDATA_THREAD_OPTION_DEFAULT,
pluginsd_worker_thread,
cd);
cd->unsafe.thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
pluginsd_worker_thread, cd);
}
}
}
@ -352,9 +360,8 @@ void *pluginsd_main(void *ptr)
closedir(dir);
}
sleep((unsigned int)scan_frequency);
pluginsd_sleep(scan_frequency);
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -33,7 +33,7 @@ struct plugind {
SPINLOCK spinlock;
bool running; // do not touch this structure after setting this to 1
bool enabled; // if this is enabled or not
netdata_thread_t thread;
ND_THREAD *thread;
pid_t pid;
} unsafe;
@ -46,7 +46,7 @@ struct plugind {
extern struct plugind *pluginsd_root;
size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp_plugin_input, FILE *fp_plugin_output, int trust_durations);
void pluginsd_process_thread_cleanup(void *ptr);
void pluginsd_process_thread_cleanup(void *pptr);
size_t pluginsd_initialize_plugin_directories();

View file

@ -6,7 +6,7 @@
#include "pluginsd_internals.h"
struct inflight_function {
uuid_t transaction;
nd_uuid_t transaction;
int code;
int timeout_s;

View file

@ -88,7 +88,7 @@ static inline void pluginsd_clear_scope_chart(PARSER *parser, const char *keywor
static inline bool pluginsd_set_scope_chart(PARSER *parser, RRDSET *st, const char *keyword) {
RRDSET *old_st = parser->user.st;
pid_t old_collector_tid = (old_st) ? old_st->pluginsd.collector_tid : 0;
pid_t my_collector_tid = gettid();
pid_t my_collector_tid = gettid_cached();
if(unlikely(old_collector_tid)) {
if(old_collector_tid != my_collector_tid) {

View file

@ -121,7 +121,7 @@ static void pluginsd_host_define_cleanup(PARSER *parser) {
parser->user.host_define.parsing_host = false;
}
static inline bool pluginsd_validate_machine_guid(const char *guid, uuid_t *uuid, char *output) {
static inline bool pluginsd_validate_machine_guid(const char *guid, nd_uuid_t *uuid, char *output) {
if(uuid_parse(guid, *uuid))
return false;
@ -231,7 +231,7 @@ static inline PARSER_RC pluginsd_host(char **words, size_t num_words, PARSER *pa
return PARSER_RC_OK;
}
uuid_t uuid;
nd_uuid_t uuid;
char uuid_str[UUID_STR_LEN];
if(!pluginsd_validate_machine_guid(guid, &uuid, uuid_str))
return PLUGINSD_DISABLE_PLUGIN(parser, PLUGINSD_KEYWORD_HOST, "cannot parse MACHINE_GUID - is it a valid UUID?");
@ -1088,7 +1088,7 @@ static inline PARSER_RC streaming_claimed_id(char **words, size_t num_words, PAR
return PARSER_RC_ERROR;
}
uuid_t uuid;
nd_uuid_t uuid;
RRDHOST *host = parser->user.host;
// We don't need the parsed UUID
@ -1130,8 +1130,9 @@ void pluginsd_cleanup_v2(PARSER *parser) {
pluginsd_clear_scope_chart(parser, "THREAD CLEANUP");
}
void pluginsd_process_thread_cleanup(void *ptr) {
PARSER *parser = (PARSER *)ptr;
void pluginsd_process_thread_cleanup(void *pptr) {
PARSER *parser = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!parser) return;
pluginsd_cleanup_v2(parser);
pluginsd_host_define_cleanup(parser);
@ -1218,54 +1219,49 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp_plugi
size_t count = 0;
// this keeps the parser with its current value
// so, parser needs to be allocated before pushing it
netdata_thread_cleanup_push(pluginsd_process_thread_cleanup, parser)
{
ND_LOG_STACK lgs[] = {
ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
ND_LOG_STACK lgs[] = {
ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
buffered_reader_init(&parser->reader);
CLEAN_BUFFER *buffer = buffer_create(sizeof(parser->reader.read_buffer) + 2, NULL);
while(likely(service_running(SERVICE_COLLECTORS))) {
CLEANUP_FUNCTION_REGISTER(pluginsd_process_thread_cleanup) cleanup_parser = parser;
buffered_reader_init(&parser->reader);
CLEAN_BUFFER *buffer = buffer_create(sizeof(parser->reader.read_buffer) + 2, NULL);
while(likely(service_running(SERVICE_COLLECTORS))) {
if(unlikely(!buffered_reader_next_line(&parser->reader, buffer))) {
buffered_reader_ret_t ret = buffered_reader_read_timeout(
&parser->reader,
fileno((FILE *) parser->fp_input),
2 * 60 * MSEC_PER_SEC, true
);
if(unlikely(!buffered_reader_next_line(&parser->reader, buffer))) {
buffered_reader_ret_t ret = buffered_reader_read_timeout(
&parser->reader,
fileno((FILE *) parser->fp_input),
2 * 60 * MSEC_PER_SEC, true
);
if(unlikely(ret != BUFFERED_READER_READ_OK))
break;
continue;
}
if(unlikely(parser_action(parser, buffer->buffer)))
if(unlikely(ret != BUFFERED_READER_READ_OK))
break;
buffer->len = 0;
buffer->buffer[0] = '\0';
continue;
}
cd->unsafe.enabled = parser->user.enabled;
count = parser->user.data_collections_count;
if(unlikely(parser_action(parser, buffer->buffer)))
break;
if(likely(count)) {
cd->successful_collections += count;
cd->serial_failures = 0;
}
else
cd->serial_failures++;
buffer->len = 0;
buffer->buffer[0] = '\0';
}
netdata_thread_cleanup_pop(1); // free parser with the pop function
cd->unsafe.enabled = parser->user.enabled;
count = parser->user.data_collections_count;
if(likely(count)) {
cd->successful_collections += count;
cd->serial_failures = 0;
}
else
cd->serial_failures++;
return count;
}

View file

@ -65,7 +65,7 @@ typedef struct parser_user_object {
struct {
bool parsing_host;
uuid_t machine_guid;
nd_uuid_t machine_guid;
char machine_guid_str[UUID_STR_LEN];
STRING *hostname;
RRDLABELS *rrdlabels;

View file

@ -84,23 +84,21 @@ static struct proc_module {
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 36
#endif
static netdata_thread_t *netdev_thread = NULL;
static ND_THREAD *netdev_thread = NULL;
static void proc_main_cleanup(void *ptr)
static void proc_main_cleanup(void *pptr)
{
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
if (netdev_thread) {
netdata_thread_join(*netdev_thread, NULL);
freez(netdev_thread);
}
nd_thread_join(netdev_thread);
worker_unregister();
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
worker_unregister();
}
bool inside_lxc_container = false;
@ -146,70 +144,67 @@ static bool log_proc_module(BUFFER *wb, void *data) {
void *proc_main(void *ptr)
{
CLEANUP_FUNCTION_REGISTER(proc_main_cleanup) cleanup_ptr = ptr;
worker_register("PROC");
rrd_collector_started();
if (config_get_boolean("plugin:proc", "/proc/net/dev", CONFIG_BOOLEAN_YES)) {
netdev_thread = mallocz(sizeof(netdata_thread_t));
netdata_log_debug(D_SYSTEM, "Starting thread %s.", THREAD_NETDEV_NAME);
netdata_thread_create(
netdev_thread, THREAD_NETDEV_NAME, NETDATA_THREAD_OPTION_JOINABLE, netdev_main, netdev_thread);
netdev_thread = nd_thread_create(THREAD_NETDEV_NAME, NETDATA_THREAD_OPTION_JOINABLE, netdev_main, NULL);
}
netdata_thread_cleanup_push(proc_main_cleanup, ptr)
{
config_get_boolean("plugin:proc", "/proc/pagetypeinfo", CONFIG_BOOLEAN_NO);
config_get_boolean("plugin:proc", "/proc/spl/kstat/zfs/pool/state", CONFIG_BOOLEAN_NO);
config_get_boolean("plugin:proc", "/proc/pagetypeinfo", CONFIG_BOOLEAN_NO);
config_get_boolean("plugin:proc", "/proc/spl/kstat/zfs/pool/state", CONFIG_BOOLEAN_NO);
// check the enabled status for each module
int i;
for(i = 0; proc_modules[i].name; i++) {
struct proc_module *pm = &proc_modules[i];
// check the enabled status for each module
int i;
for(i = 0; proc_modules[i].name; i++) {
struct proc_module *pm = &proc_modules[i];
pm->enabled = config_get_boolean("plugin:proc", pm->name, CONFIG_BOOLEAN_YES);
pm->rd = NULL;
pm->enabled = config_get_boolean("plugin:proc", pm->name, CONFIG_BOOLEAN_YES);
pm->rd = NULL;
worker_register_job_name(i, proc_modules[i].dim);
}
worker_register_job_name(i, proc_modules[i].dim);
}
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
inside_lxc_container = is_lxcfs_proc_mounted();
inside_lxc_container = is_lxcfs_proc_mounted();
#define LGS_MODULE_ID 0
ND_LOG_STACK lgs[] = {
[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin"),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
ND_LOG_STACK lgs[] = {
[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin"),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
while(service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
while(service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(!service_running(SERVICE_COLLECTORS)))
break;
for(i = 0; proc_modules[i].name; i++) {
if(unlikely(!service_running(SERVICE_COLLECTORS)))
break;
for(i = 0; proc_modules[i].name; i++) {
if(unlikely(!service_running(SERVICE_COLLECTORS)))
break;
struct proc_module *pm = &proc_modules[i];
if(unlikely(!pm->enabled))
continue;
struct proc_module *pm = &proc_modules[i];
if(unlikely(!pm->enabled))
continue;
worker_is_busy(i);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_proc_module, pm);
pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin");
}
worker_is_busy(i);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_proc_module, pm);
pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin");
}
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -9,7 +9,7 @@
#define PLUGIN_PROC_NAME PLUGIN_PROC_CONFIG_NAME ".plugin"
#define THREAD_NETDEV_NAME "P[proc netdev]"
void *netdev_main(void *ptr);
void *netdev_main(void *ptr_is_null);
int do_proc_net_wireless(int update_every, usec_t dt);
int do_proc_diskstats(int update_every, usec_t dt);

View file

@ -2,10 +2,13 @@
#include "plugin_proc.h"
#define RRD_TYPE_DISK "disk"
#define PLUGIN_PROC_MODULE_DISKSTATS_NAME "/proc/diskstats"
#define CONFIG_SECTION_PLUGIN_PROC_DISKSTATS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_DISKSTATS_NAME
#define _COMMON_PLUGIN_NAME PLUGIN_PROC_CONFIG_NAME
#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_DISKSTATS_NAME
#include "../common-contexts/common-contexts.h"
#define RRDFUNCTIONS_DISKSTATS_HELP "View block device statistics"
#define DISK_TYPE_UNKNOWN 0
@ -75,9 +78,7 @@ static struct disk {
usec_t bcache_priority_stats_update_every_usec;
usec_t bcache_priority_stats_elapsed_usec;
RRDSET *st_io;
RRDDIM *rd_io_reads;
RRDDIM *rd_io_writes;
ND_DISK_IO disk_io;
RRDSET *st_ext_io;
RRDDIM *rd_io_discards;
@ -1033,6 +1034,10 @@ static void add_labels_to_disk(struct disk *d, RRDSET *st) {
rrdlabels_add(st->rrdlabels, "device_type", get_disk_type_string(d->type), RRDLABEL_SRC_AUTO);
}
static void disk_labels_cb(RRDSET *st, void *data) {
add_labels_to_disk(data, st);
}
static int diskstats_function_block_devices(BUFFER *wb, const char *function __maybe_unused) {
buffer_flush(wb);
wb->content_type = CT_APPLICATION_JSON;
@ -1076,8 +1081,8 @@ static int diskstats_function_block_devices(BUFFER *wb, const char *function __m
buffer_json_add_array_item_string(wb, d->serial);
// IO
double io_reads = rrddim_get_last_stored_value(d->rd_io_reads, &max_io_reads, 1024.0);
double io_writes = rrddim_get_last_stored_value(d->rd_io_writes, &max_io_writes, 1024.0);
double io_reads = rrddim_get_last_stored_value(d->disk_io.rd_io_reads, &max_io_reads, 1024.0);
double io_writes = rrddim_get_last_stored_value(d->disk_io.rd_io_writes, &max_io_writes, 1024.0);
double io_total = NAN;
if (!isnan(io_reads) && !isnan(io_writes)) {
io_total = io_reads + io_writes;
@ -1328,7 +1333,7 @@ static void diskstats_cleanup_disks() {
rrdset_obsolete_and_pointer_null(d->st_ext_await);
rrdset_obsolete_and_pointer_null(d->st_backlog);
rrdset_obsolete_and_pointer_null(d->st_busy);
rrdset_obsolete_and_pointer_null(d->st_io);
rrdset_obsolete_and_pointer_null(d->disk_io.st_io);
rrdset_obsolete_and_pointer_null(d->st_ext_io);
rrdset_obsolete_and_pointer_null(d->st_iotime);
rrdset_obsolete_and_pointer_null(d->st_ext_iotime);
@ -1616,31 +1621,17 @@ int do_proc_diskstats(int update_every, usec_t dt) {
netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
d->do_io = CONFIG_BOOLEAN_YES;
if(unlikely(!d->st_io)) {
d->st_io = rrdset_create_localhost(
RRD_TYPE_DISK
, d->chart_id
, d->disk
, family
, "disk.io"
, "Disk I/O Bandwidth"
, "KiB/s"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_DISKSTATS_NAME
, NETDATA_CHART_PRIO_DISK_IO
, update_every
, RRDSET_TYPE_AREA
);
last_readsectors = d->disk_io.rd_io_reads ? d->disk_io.rd_io_reads->collector.last_collected_value : 0;
last_writesectors = d->disk_io.rd_io_writes ? d->disk_io.rd_io_writes->collector.last_collected_value : 0;
d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL);
d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL);
add_labels_to_disk(d, d->st_io);
}
last_readsectors = rrddim_set_by_pointer(d->st_io, d->rd_io_reads, readsectors);
last_writesectors = rrddim_set_by_pointer(d->st_io, d->rd_io_writes, writesectors);
rrdset_done(d->st_io);
common_disk_io(&d->disk_io,
d->chart_id,
d->disk,
readsectors * d->sector_size,
writesectors * d->sector_size,
update_every,
disk_labels_cb,
d);
}
if (do_dc_stats && d->do_io == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@ -2468,32 +2459,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
if(global_do_io == CONFIG_BOOLEAN_YES || (global_do_io == CONFIG_BOOLEAN_AUTO &&
(system_read_kb || system_write_kb ||
netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
static RRDSET *st_io = NULL;
static RRDDIM *rd_in = NULL, *rd_out = NULL;
if(unlikely(!st_io)) {
st_io = rrdset_create_localhost(
"system"
, "io"
, NULL
, "disk"
, NULL
, "Disk I/O"
, "KiB/s"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_DISKSTATS_NAME
, NETDATA_CHART_PRIO_SYSTEM_IO
, update_every
, RRDSET_TYPE_AREA
);
rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_io, rd_in, system_read_kb);
rrddim_set_by_pointer(st_io, rd_out, system_write_kb);
rrdset_done(st_io);
common_system_io(system_read_kb * 1024, system_write_kb * 1024, update_every);
}
return 0;

View file

@ -48,7 +48,7 @@ int do_proc_loadavg(int update_every, usec_t dt) {
unsigned long long active_processes = str2ull(procfile_lineword(ff, 0, 4), NULL);
//get system pid_max
unsigned long long max_processes = get_system_pid_max();
unsigned long long max_processes = os_get_system_pid_max();
//
//unsigned long long next_pid = str2ull(procfile_lineword(ff, 0, 5));

View file

@ -5,6 +5,10 @@
#define PLUGIN_PROC_MODULE_MEMINFO_NAME "/proc/meminfo"
#define CONFIG_SECTION_PLUGIN_PROC_MEMINFO "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_MEMINFO_NAME
#define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME
#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_MEMINFO_NAME
#include "../common-contexts/common-contexts.h"
int do_proc_meminfo(int update_every, usec_t dt) {
(void)dt;
@ -242,65 +246,10 @@ int do_proc_meminfo(int update_every, usec_t dt) {
}
if(do_ram) {
{
static RRDSET *st_system_ram = NULL;
static RRDDIM *rd_free = NULL, *rd_used = NULL, *rd_cached = NULL, *rd_buffers = NULL;
common_system_ram(MemFree * 1024, MemUsed * 1024, MemCached * 1024, Buffers * 1024, update_every);
if(unlikely(!st_system_ram)) {
st_system_ram = rrdset_create_localhost(
"system"
, "ram"
, NULL
, "ram"
, NULL
, "System RAM"
, "MiB"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_SYSTEM_RAM
, update_every
, RRDSET_TYPE_STACKED
);
rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
rrddim_set_by_pointer(st_system_ram, rd_free, MemFree);
rrddim_set_by_pointer(st_system_ram, rd_used, MemUsed);
rrddim_set_by_pointer(st_system_ram, rd_cached, MemCached);
rrddim_set_by_pointer(st_system_ram, rd_buffers, Buffers);
rrdset_done(st_system_ram);
}
if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND) {
static RRDSET *st_mem_available = NULL;
static RRDDIM *rd_avail = NULL;
if(unlikely(!st_mem_available)) {
st_mem_available = rrdset_create_localhost(
"mem"
, "available"
, NULL
, "overview"
, NULL
, "Available RAM for applications"
, "MiB"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE
, update_every
, RRDSET_TYPE_AREA
);
rd_avail = rrddim_add(st_mem_available, "MemAvailable", "avail", 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
rrddim_set_by_pointer(st_mem_available, rd_avail, MemAvailable);
rrdset_done(st_mem_available);
}
if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND)
common_mem_available(MemAvailable * 1024, update_every);
}
unsigned long long SwapUsed = SwapTotal - SwapFree;
@ -309,35 +258,7 @@ int do_proc_meminfo(int update_every, usec_t dt) {
(SwapTotal || SwapUsed || SwapFree ||
netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
do_swap = CONFIG_BOOLEAN_YES;
static RRDSET *st_system_swap = NULL;
static RRDDIM *rd_free = NULL, *rd_used = NULL;
if(unlikely(!st_system_swap)) {
st_system_swap = rrdset_create_localhost(
"mem"
, "swap"
, NULL
, "swap"
, NULL
, "System Swap"
, "MiB"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_MEMINFO_NAME
, NETDATA_CHART_PRIO_MEM_SWAP
, update_every
, RRDSET_TYPE_STACKED
);
rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL);
rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
rrddim_set_by_pointer(st_system_swap, rd_used, SwapUsed);
rrddim_set_by_pointer(st_system_swap, rd_free, SwapFree);
rrdset_done(st_system_swap);
common_mem_swap(SwapFree * 1024, SwapUsed * 1024, update_every);
{
static RRDSET *st_mem_swap_cached = NULL;

View file

@ -1738,17 +1738,19 @@ int do_proc_net_dev(int update_every, usec_t dt) {
return 0;
}
static void netdev_main_cleanup(void *ptr)
{
UNUSED(ptr);
static void netdev_main_cleanup(void *pptr) {
if(CLEANUP_FUNCTION_GET_PTR(pptr) != (void *)0x01)
return;
collector_info("cleaning up...");
worker_unregister();
}
void *netdev_main(void *ptr)
void *netdev_main(void *ptr_is_null __maybe_unused)
{
CLEANUP_FUNCTION_REGISTER(netdev_main_cleanup) cleanup_ptr = (void *)0x01;
worker_register("NETDEV");
worker_register_job_name(0, "netdev");
@ -1760,29 +1762,26 @@ void *netdev_main(void *ptr)
"top", HTTP_ACCESS_ANONYMOUS_DATA,
netdev_function_net_interfaces);
netdata_thread_cleanup_push(netdev_main_cleanup, ptr) {
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
while (service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
while (service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
if (unlikely(!service_running(SERVICE_COLLECTORS)))
break;
if (unlikely(!service_running(SERVICE_COLLECTORS)))
break;
cgroup_netdev_reset_all();
cgroup_netdev_reset_all();
worker_is_busy(0);
worker_is_busy(0);
netdata_mutex_lock(&netdev_mutex);
if (do_proc_net_dev(localhost->rrd_update_every, hb_dt))
break;
netdata_mutex_unlock(&netdev_mutex);
}
netdata_mutex_lock(&netdev_mutex);
if (do_proc_net_dev(localhost->rrd_update_every, hb_dt))
break;
netdata_mutex_unlock(&netdev_mutex);
}
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -400,8 +400,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_AREA
);
rd_received = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_received = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_received, Ip6InOctets);
@ -438,10 +438,10 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_received = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_forwarded = rrddim_add(st, "OutForwDatagrams", "forwarded", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_delivers = rrddim_add(st, "InDelivers", "delivers", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_forwarded = rrddim_add(st, "forwarded", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_delivers = rrddim_add(st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_received, Ip6InReceives);
@ -619,8 +619,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_received, Udp6InDatagrams);
@ -703,8 +703,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_received, UdpLite6InDatagrams);
@ -786,8 +786,8 @@ static void do_proc_net_snmp6(int update_every) {
);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
rd_Ip6InMcastOctets = rrddim_add(st, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutMcastOctets = rrddim_add(st, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6InMcastOctets = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutMcastOctets = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_Ip6InMcastOctets, Ip6InMcastOctets);
@ -821,8 +821,8 @@ static void do_proc_net_snmp6(int update_every) {
);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
rd_Ip6InBcastOctets = rrddim_add(st, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutBcastOctets = rrddim_add(st, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6InBcastOctets = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutBcastOctets = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_Ip6InBcastOctets, Ip6InBcastOctets);
@ -856,8 +856,8 @@ static void do_proc_net_snmp6(int update_every) {
);
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
rd_Ip6InMcastPkts = rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutMcastPkts = rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6InMcastPkts = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Ip6OutMcastPkts = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_Ip6InMcastPkts, Ip6InMcastPkts);
@ -890,8 +890,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_Icmp6InMsgs = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6OutMsgs = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6InMsgs = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6OutMsgs = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_Icmp6InMsgs, Icmp6InMsgs);
@ -924,8 +924,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_Icmp6InRedirects = rrddim_add(st, "InRedirects", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6OutRedirects = rrddim_add(st, "OutRedirects", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6InRedirects = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_Icmp6OutRedirects = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_Icmp6InRedirects, Icmp6InRedirects);
@ -1203,8 +1203,8 @@ static void do_proc_net_snmp6(int update_every) {
, RRDSET_TYPE_LINE
);
rd_InMLDv2Reports = rrddim_add(st, "InMLDv2Reports", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutMLDv2Reports = rrddim_add(st, "OutMLDv2Reports", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InMLDv2Reports = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutMLDv2Reports = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_InMLDv2Reports, Icmp6InMLDv2Reports);
@ -1865,8 +1865,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_AREA
);
rd_in = rrddim_add(st_system_ip, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_system_ip, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_in = rrddim_add(st_system_ip, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_system_ip, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_system_ip, rd_in, ipext_InOctets);
@ -1900,8 +1900,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
rrdset_flag_set(st_ip_mcast, RRDSET_FLAG_DETAIL);
rd_in = rrddim_add(st_ip_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_in = rrddim_add(st_ip_mcast, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_mcast, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_ip_mcast, rd_in, ipext_InMcastOctets);
@ -1939,8 +1939,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
rrdset_flag_set(st_ip_bcast, RRDSET_FLAG_DETAIL);
rd_in = rrddim_add(st_ip_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_in = rrddim_add(st_ip_bcast, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_bcast, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_ip_bcast, rd_in, ipext_InBcastOctets);
@ -1978,8 +1978,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
rrdset_flag_set(st_ip_mcastpkts, RRDSET_FLAG_DETAIL);
rd_in = rrddim_add(st_ip_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_in = rrddim_add(st_ip_mcastpkts, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_mcastpkts, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_ip_mcastpkts, rd_in, ipext_InMcastPkts);
@ -2014,8 +2014,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
rrdset_flag_set(st_ip_bcastpkts, RRDSET_FLAG_DETAIL);
rd_in = rrddim_add(st_ip_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_in = rrddim_add(st_ip_bcastpkts, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_out = rrddim_add(st_ip_bcastpkts, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_ip_bcastpkts, rd_in, ipext_InBcastPkts);
@ -2253,9 +2253,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_received = rrddim_add(st_syncookies, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st_syncookies, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_failed = rrddim_add(st_syncookies, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_received = rrddim_add(st_syncookies, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st_syncookies, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_failed = rrddim_add(st_syncookies, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_syncookies, rd_received, tcpext_SyncookiesRecv);
@ -2369,10 +2369,10 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_InReceives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutRequests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_ForwDatagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InDelivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InReceives = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutRequests = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_ForwDatagrams = rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InDelivers = rrddim_add(st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_OutRequests, (collected_number)snmp_root.ip_OutRequests);
@ -2557,8 +2557,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_InMsgs = rrddim_add(st_packets, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutMsgs = rrddim_add(st_packets, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InMsgs = rrddim_add(st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutMsgs = rrddim_add(st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_packets, rd_InMsgs, (collected_number)snmp_root.icmp_InMsgs);
@ -2773,8 +2773,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_InSegs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutSegs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InSegs = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutSegs = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_InSegs, (collected_number)snmp_root.tcp_InSegs);
@ -2932,8 +2932,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InDatagrams = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutDatagrams = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udp_InDatagrams);
@ -3030,8 +3030,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
, RRDSET_TYPE_LINE
);
rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_InDatagrams = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_OutDatagrams = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udplite_InDatagrams);

View file

@ -484,7 +484,7 @@ int do_proc_stat(int update_every, usec_t dt) {
*time_in_state_filename = NULL, *schedstat_filename = NULL, *cpuidle_name_filename = NULL, *cpuidle_time_filename = NULL;
static const RRDVAR_ACQUIRED *cpus_var = NULL;
static int accurate_freq_avail = 0, accurate_freq_is_used = 0;
size_t cores_found = (size_t)get_system_cpus();
size_t cores_found = (size_t)os_get_system_cpus();
if(unlikely(do_cpu == -1)) {
do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", CONFIG_BOOLEAN_YES);
@ -495,7 +495,7 @@ int do_proc_stat(int update_every, usec_t dt) {
do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", CONFIG_BOOLEAN_YES);
// give sane defaults based on the number of processors
if(unlikely(get_system_cpus() > 128)) {
if(unlikely(os_get_system_cpus() > 128)) {
// the system has too many processors
keep_per_core_fds_open = CONFIG_BOOLEAN_NO;
do_core_throttle_count = CONFIG_BOOLEAN_NO;
@ -511,7 +511,7 @@ int do_proc_stat(int update_every, usec_t dt) {
do_cpu_freq = CONFIG_BOOLEAN_YES;
do_cpuidle = CONFIG_BOOLEAN_NO;
}
if(unlikely(get_system_cpus() > 24)) {
if(unlikely(os_get_system_cpus() > 24)) {
// the system has too many processors
keep_cpuidle_fds_open = CONFIG_BOOLEAN_NO;
}

View file

@ -6,6 +6,10 @@
#define OOM_KILL_STRING "oom_kill"
#define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME
#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_VMSTAT_NAME
#include "../common-contexts/common-contexts.h"
int do_proc_vmstat(int update_every, usec_t dt) {
(void)dt;
@ -328,34 +332,7 @@ int do_proc_vmstat(int update_every, usec_t dt) {
// --------------------------------------------------------------------
if(do_pgfaults) {
static RRDSET *st_pgfaults = NULL;
static RRDDIM *rd_minor = NULL, *rd_major = NULL;
if(unlikely(!st_pgfaults)) {
st_pgfaults = rrdset_create_localhost(
"mem"
, "pgfaults"
, NULL
, "page faults"
, NULL
, "Memory Page Faults"
, "faults/s"
, PLUGIN_PROC_NAME
, PLUGIN_PROC_MODULE_VMSTAT_NAME
, NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS
, update_every
, RRDSET_TYPE_LINE
);
rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st_pgfaults, rd_minor, pgfault);
rrddim_set_by_pointer(st_pgfaults, rd_major, pgmajfault);
rrdset_done(st_pgfaults);
common_mem_pgfaults(pgfault, pgmajfault, update_every);
}
// --------------------------------------------------------------------

View file

@ -180,8 +180,10 @@ static void *subprofile_main(void* Arg) {
return nullptr;
}
static void profile_main_cleanup(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *) ptr;
static void profile_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
netdata_log_info("cleaning up...");
@ -190,7 +192,7 @@ static void profile_main_cleanup(void *ptr) {
}
extern "C" void *profile_main(void *ptr) {
netdata_thread_cleanup_push(profile_main_cleanup, ptr);
CLEANUP_FUNCTION_REGISTER(profile_main_cleanup) cleanup_ptr = ptr;
int UpdateEvery = (int) config_get_number(CONFIG_SECTION_PROFILE, "update every", 1);
if (UpdateEvery < localhost->rrd_update_every)
@ -209,18 +211,18 @@ extern "C" void *profile_main(void *ptr) {
Profilers.push_back(P);
}
std::vector<netdata_thread_t> Threads(NumThreads);
std::vector<ND_THREAD *> Threads(NumThreads);
for (size_t Idx = 0; Idx != NumThreads; Idx++) {
char Tag[NETDATA_THREAD_TAG_MAX + 1];
snprintfz(Tag, NETDATA_THREAD_TAG_MAX, "PROFILER[%zu]", Idx);
netdata_thread_create(&Threads[Idx], Tag, NETDATA_THREAD_OPTION_JOINABLE, subprofile_main, static_cast<void *>(&Profilers[Idx]));
Threads[Idx] = nd_thread_create(Tag, NETDATA_THREAD_OPTION_JOINABLE,
subprofile_main, static_cast<void *>(&Profilers[Idx]));
}
for (size_t Idx = 0; Idx != NumThreads; Idx++)
netdata_thread_join(Threads[Idx], nullptr);
nd_thread_join(Threads[Idx]);
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -237,7 +237,7 @@ struct collection_thread_status {
bool running;
uint32_t max_sockets;
netdata_thread_t thread;
ND_THREAD *thread;
};
static struct statsd {
@ -1078,8 +1078,10 @@ static int statsd_snd_callback(POLLINFO *pi, short int *events) {
// --------------------------------------------------------------------------------------------------------------------
// statsd child thread to collect metrics from network
void statsd_collector_thread_cleanup(void *data) {
struct statsd_udp *d = data;
void statsd_collector_thread_cleanup(void *pptr) {
struct statsd_udp *d = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!d) return;
spinlock_lock(&d->status->spinlock);
d->status->running = false;
spinlock_unlock(&d->status->spinlock);
@ -1115,12 +1117,12 @@ void *statsd_collector_thread(void *ptr) {
worker_register_job_name(WORKER_JOB_TYPE_RCV_DATA, "receive");
worker_register_job_name(WORKER_JOB_TYPE_SND_DATA, "send");
collector_info("STATSD collector thread started with taskid %d", gettid());
collector_info("STATSD collector thread started with taskid %d", gettid_cached());
struct statsd_udp *d = callocz(sizeof(struct statsd_udp), 1);
d->status = status;
netdata_thread_cleanup_push(statsd_collector_thread_cleanup, d);
CLEANUP_FUNCTION_REGISTER(statsd_collector_thread_cleanup) cleanup_ptr = d;
#ifdef HAVE_RECVMMSG
d->type = STATSD_SOCKET_DATA_TYPE_UDP;
@ -1154,7 +1156,6 @@ void *statsd_collector_thread(void *ptr) {
, status->max_sockets
);
netdata_thread_cleanup_pop(1);
return NULL;
}
@ -2393,8 +2394,10 @@ static int statsd_listen_sockets_setup(void) {
return listen_sockets_setup(&statsd.sockets);
}
static void statsd_main_cleanup(void *data) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
static void statsd_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
@ -2402,13 +2405,14 @@ static void statsd_main_cleanup(void *data) {
int i;
for (i = 0; i < statsd.threads; i++) {
spinlock_lock(&statsd.collection_threads_status[i].spinlock);
if(statsd.collection_threads_status[i].running) {
collector_info("STATSD: stopping data collection thread %d...", i + 1);
netdata_thread_cancel(statsd.collection_threads_status[i].thread);
collector_info("STATSD: signalling data collection thread %d to stop...", i + 1);
nd_thread_signal_cancel(statsd.collection_threads_status[i].thread);
}
else {
else
collector_info("STATSD: data collection thread %d found stopped.", i + 1);
}
spinlock_unlock(&statsd.collection_threads_status[i].spinlock);
}
}
@ -2445,6 +2449,8 @@ static void statsd_main_cleanup(void *data) {
#endif
void *statsd_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(statsd_main_cleanup) cleanup_ptr = ptr;
worker_register("STATSDFLUSH");
worker_register_job_name(WORKER_STATSD_FLUSH_GAUGES, "gauges");
worker_register_job_name(WORKER_STATSD_FLUSH_COUNTERS, "counters");
@ -2455,8 +2461,6 @@ void *statsd_main(void *ptr) {
worker_register_job_name(WORKER_STATSD_FLUSH_DICTIONARIES, "dictionaries");
worker_register_job_name(WORKER_STATSD_FLUSH_STATS, "statistics");
netdata_thread_cleanup_push(statsd_main_cleanup, ptr);
statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
@ -2585,7 +2589,8 @@ void *statsd_main(void *ptr) {
char tag[NETDATA_THREAD_TAG_MAX + 1];
snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STATSD_IN[%d]", i + 1);
spinlock_init(&statsd.collection_threads_status[i].spinlock);
netdata_thread_create(&statsd.collection_threads_status[i].thread, tag, NETDATA_THREAD_OPTION_DEFAULT, statsd_collector_thread, &statsd.collection_threads_status[i]);
statsd.collection_threads_status[i].thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
statsd_collector_thread, &statsd.collection_threads_status[i]);
}
// ----------------------------------------------------------------------------------------------------------------
@ -2887,6 +2892,5 @@ void *statsd_main(void *ptr) {
}
cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -19,7 +19,7 @@ static bool journal_data_directories_exist() {
int main(int argc __maybe_unused, char **argv __maybe_unused) {
clocks_init();
netdata_thread_set_tag("sd-jrnl.plugin");
nd_thread_tag_set("sd-jrnl.plugin");
nd_log_initialize_for_external_plugins("systemd-journal.plugin");
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
@ -67,9 +67,7 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
// ------------------------------------------------------------------------
// watcher thread
netdata_thread_t watcher_thread;
netdata_thread_create(&watcher_thread, "SDWATCH",
NETDATA_THREAD_OPTION_DONT_LOG, journal_watcher_main, NULL);
nd_thread_create("SDWATCH", NETDATA_THREAD_OPTION_DONT_LOG, journal_watcher_main, NULL);
// ------------------------------------------------------------------------
// the event loop for functions

View file

@ -848,12 +848,13 @@ static inline void tc_split_words(char *str, char **words, int max_words) {
static pid_t tc_child_pid = 0;
static void tc_main_cleanup(void *ptr) {
worker_unregister();
static void tc_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
worker_unregister();
tc_device_index_destroy();
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
@ -892,6 +893,8 @@ static void tc_main_cleanup(void *ptr) {
#endif
void *tc_main(void *ptr) {
CLEANUP_FUNCTION_REGISTER(tc_main_cleanup) cleanup_ptr = ptr;
worker_register("TC");
worker_register_job_name(WORKER_TC_CLASS, "class");
worker_register_job_name(WORKER_TC_BEGIN, "begin");
@ -909,7 +912,6 @@ void *tc_main(void *ptr) {
worker_register_job_custom_metric(WORKER_TC_CLASSES, "number of classes", "classes", WORKER_METRIC_ABSOLUTE);
tc_device_index_init();
netdata_thread_cleanup_push(tc_main_cleanup, ptr);
char command[FILENAME_MAX + 1];
char *words[PLUGINSD_MAX_WORDS] = { NULL };
@ -1036,10 +1038,8 @@ void *tc_main(void *ptr) {
// netdata_log_debug(D_TC_LOOP, "END line");
if(likely(device)) {
netdata_thread_disable_cancelability();
tc_device_commit(device);
// tc_device_free(device);
netdata_thread_enable_cancelability();
}
device = NULL;
@ -1177,7 +1177,5 @@ void *tc_main(void *ptr) {
}
cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement
worker_unregister();
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "daemon/common.h"
#include "libnetdata/os.h"
#include "libnetdata/os/os.h"
#define PLUGIN_TIMEX_NAME "timex.plugin"
@ -30,25 +30,25 @@ struct status_codes {
{NULL, 0, NULL},
};
static void timex_main_cleanup(void *ptr)
static void timex_main_cleanup(void *pptr)
{
worker_unregister();
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
netdata_log_info("cleaning up...");
worker_unregister();
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
}
void *timex_main(void *ptr)
{
CLEANUP_FUNCTION_REGISTER(timex_main_cleanup) cleanup_ptr = ptr;
worker_register("TIMEX");
worker_register_job_name(0, "clock check");
netdata_thread_cleanup_push(timex_main_cleanup, ptr);
int update_every = (int)config_get_number(CONFIG_SECTION_TIMEX, "update every", 10);
if (update_every < localhost->rrd_update_every)
update_every = localhost->rrd_update_every;
@ -73,7 +73,7 @@ void *timex_main(void *ptr)
int sync_state = 0;
static int prev_sync_state = 0;
sync_state = ADJUST_TIMEX(&timex_buf);
sync_state = os_adjtimex(&timex_buf);
int non_seq_failure = (sync_state == -1 && prev_sync_state != -1);
prev_sync_state = sync_state;
@ -171,6 +171,5 @@ void *timex_main(void *ptr)
}
exit:
netdata_thread_cleanup_pop(1);
return NULL;
}

View file

@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
int do_GetSystemCPU(int update_every, usec_t dt __maybe_unused) {
FILETIME idleTime, kernelTime, userTime;
if(GetSystemTimes(&idleTime, &kernelTime, &userTime) == 0) {
netdata_log_error("GetSystemTimes() failed.");
return 1;
}
ULONGLONG idle = FileTimeToULL(idleTime);
ULONGLONG kernel = FileTimeToULL(kernelTime);
ULONGLONG user = FileTimeToULL(userTime);
// kernel includes idle
kernel -= idle;
static RRDSET *st = NULL;
static RRDDIM *rd_user = NULL, *rd_kernel = NULL, *rd_idle = NULL;
if(!st) {
st = rrdset_create_localhost(
"system"
, "cpu"
, NULL
, "cpu"
, "system.cpu"
, "Total CPU utilization"
, "percentage"
, PLUGIN_WINDOWS_NAME
, "GetSystemTimes"
, NETDATA_CHART_PRIO_SYSTEM_CPU
, update_every
, RRDSET_TYPE_STACKED
);
rd_user = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rd_kernel = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rd_idle = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(st, "idle");
}
rrddim_set_by_pointer(st, rd_user, (collected_number )user);
rrddim_set_by_pointer(st, rd_kernel, (collected_number )kernel);
rrddim_set_by_pointer(st, rd_idle, (collected_number )idle);
rrdset_done(st);
return 0;
}

View file

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
#define _COMMON_PLUGIN_NAME "windows.plugin"
#define _COMMON_PLUGIN_MODULE_NAME "GetSystemRam"
#include "../common-contexts/common-contexts.h"
int do_GetSystemRAM(int update_every, usec_t dt __maybe_unused) {
MEMORYSTATUSEX memStat = { 0 };
memStat.dwLength = sizeof(memStat);
if (!GlobalMemoryStatusEx(&memStat)) {
netdata_log_error("GlobalMemoryStatusEx() failed.");
return 1;
}
{
ULONGLONG total_bytes = memStat.ullTotalPhys;
ULONGLONG free_bytes = memStat.ullAvailPhys;
ULONGLONG used_bytes = total_bytes - free_bytes;
common_system_ram(free_bytes, used_bytes, update_every);
}
{
DWORDLONG total_bytes = memStat.ullTotalPageFile;
DWORDLONG free_bytes = memStat.ullAvailPageFile;
DWORDLONG used_bytes = total_bytes - free_bytes;
common_mem_swap(free_bytes, used_bytes, update_every);
}
return 0;
}

View file

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
int do_GetSystemUptime(int update_every, usec_t dt __maybe_unused) {
ULONGLONG uptime = GetTickCount64(); // in milliseconds
static RRDSET *st = NULL;
static RRDDIM *rd_uptime = NULL;
if (!st) {
st = rrdset_create_localhost(
"system"
, "uptime"
, NULL
, "uptime"
, "system.uptime"
, "System Uptime"
, "seconds"
, PLUGIN_WINDOWS_NAME
, "GetSystemUptime"
, NETDATA_CHART_PRIO_SYSTEM_UPTIME
, update_every
, RRDSET_TYPE_LINE
);
rd_uptime = rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
}
rrddim_set_by_pointer(st, rd_uptime, (collected_number)uptime);
rrdset_done(st);
return 0;
}

View file

@ -0,0 +1,529 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "perflib.h"
#include "windows-internals.h"
static const char *getCounterType(DWORD CounterType) {
switch (CounterType) {
case PERF_COUNTER_COUNTER:
return "PERF_COUNTER_COUNTER";
case PERF_COUNTER_TIMER:
return "PERF_COUNTER_TIMER";
case PERF_COUNTER_QUEUELEN_TYPE:
return "PERF_COUNTER_QUEUELEN_TYPE";
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
return "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
return "PERF_COUNTER_100NS_QUEUELEN_TYPE";
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
return "PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE";
case PERF_COUNTER_BULK_COUNT:
return "PERF_COUNTER_BULK_COUNT";
case PERF_COUNTER_TEXT:
return "PERF_COUNTER_TEXT";
case PERF_COUNTER_RAWCOUNT:
return "PERF_COUNTER_RAWCOUNT";
case PERF_COUNTER_LARGE_RAWCOUNT:
return "PERF_COUNTER_LARGE_RAWCOUNT";
case PERF_COUNTER_RAWCOUNT_HEX:
return "PERF_COUNTER_RAWCOUNT_HEX";
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
return "PERF_COUNTER_LARGE_RAWCOUNT_HEX";
case PERF_SAMPLE_FRACTION:
return "PERF_SAMPLE_FRACTION";
case PERF_SAMPLE_COUNTER:
return "PERF_SAMPLE_COUNTER";
case PERF_COUNTER_NODATA:
return "PERF_COUNTER_NODATA";
case PERF_COUNTER_TIMER_INV:
return "PERF_COUNTER_TIMER_INV";
case PERF_SAMPLE_BASE:
return "PERF_SAMPLE_BASE";
case PERF_AVERAGE_TIMER:
return "PERF_AVERAGE_TIMER";
case PERF_AVERAGE_BASE:
return "PERF_AVERAGE_BASE";
case PERF_AVERAGE_BULK:
return "PERF_AVERAGE_BULK";
case PERF_OBJ_TIME_TIMER:
return "PERF_OBJ_TIME_TIMER";
case PERF_100NSEC_TIMER:
return "PERF_100NSEC_TIMER";
case PERF_100NSEC_TIMER_INV:
return "PERF_100NSEC_TIMER_INV";
case PERF_COUNTER_MULTI_TIMER:
return "PERF_COUNTER_MULTI_TIMER";
case PERF_COUNTER_MULTI_TIMER_INV:
return "PERF_COUNTER_MULTI_TIMER_INV";
case PERF_COUNTER_MULTI_BASE:
return "PERF_COUNTER_MULTI_BASE";
case PERF_100NSEC_MULTI_TIMER:
return "PERF_100NSEC_MULTI_TIMER";
case PERF_100NSEC_MULTI_TIMER_INV:
return "PERF_100NSEC_MULTI_TIMER_INV";
case PERF_RAW_FRACTION:
return "PERF_RAW_FRACTION";
case PERF_LARGE_RAW_FRACTION:
return "PERF_LARGE_RAW_FRACTION";
case PERF_RAW_BASE:
return "PERF_RAW_BASE";
case PERF_LARGE_RAW_BASE:
return "PERF_LARGE_RAW_BASE";
case PERF_ELAPSED_TIME:
return "PERF_ELAPSED_TIME";
case PERF_COUNTER_HISTOGRAM_TYPE:
return "PERF_COUNTER_HISTOGRAM_TYPE";
case PERF_COUNTER_DELTA:
return "PERF_COUNTER_DELTA";
case PERF_COUNTER_LARGE_DELTA:
return "PERF_COUNTER_LARGE_DELTA";
case PERF_PRECISION_SYSTEM_TIMER:
return "PERF_PRECISION_SYSTEM_TIMER";
case PERF_PRECISION_100NS_TIMER:
return "PERF_PRECISION_100NS_TIMER";
case PERF_PRECISION_OBJECT_TIMER:
return "PERF_PRECISION_OBJECT_TIMER";
default:
return "UNKNOWN_COUNTER_TYPE";
}
}
static const char *getCounterDescription(DWORD CounterType) {
switch (CounterType) {
case PERF_COUNTER_COUNTER:
return "32-bit Counter. Divide delta by delta time. Display suffix: \"/sec\"";
case PERF_COUNTER_TIMER:
return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\"";
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
return "Queue Length Space-Time Product. Divide delta by delta time. No Display Suffix";
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
return "Queue Length Space-Time Product using 100 Ns timebase. Divide delta by delta time. No Display Suffix";
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
return "Queue Length Space-Time Product using Object specific timebase. Divide delta by delta time. No Display Suffix.";
case PERF_COUNTER_BULK_COUNT:
return "64-bit Counter. Divide delta by delta time. Display Suffix: \"/sec\"";
case PERF_COUNTER_TEXT:
return "Unicode text Display as text.";
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT:
return "A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
return "Special case for RAWCOUNT which should be displayed in hex. A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
case PERF_SAMPLE_FRACTION:
return "A count which is either 1 or 0 on each sampling interrupt (% busy). Divide delta by delta base. Display Suffix: \"%\"";
case PERF_SAMPLE_COUNTER:
return "A count which is sampled on each sampling interrupt (queue length). Divide delta by delta time. No Display Suffix.";
case PERF_COUNTER_NODATA:
return "A label: no data is associated with this counter (it has 0 length). Do not display.";
case PERF_COUNTER_TIMER_INV:
return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
case PERF_SAMPLE_BASE:
return "The divisor for a sample, used with the previous counter to form a sampled %. You must check for >0 before dividing by this! This counter will directly follow the numerator counter. It should not be displayed to the user.";
case PERF_AVERAGE_TIMER:
return "A timer which, when divided by an average base, produces a time in seconds which is the average time of some operation. This timer times total operations, and the base is the number of operations. Display Suffix: \"sec\"";
case PERF_AVERAGE_BASE:
return "Used as the denominator in the computation of time or count averages. Must directly follow the numerator counter. Not displayed to the user.";
case PERF_AVERAGE_BULK:
return "A bulk count which, when divided (typically) by the number of operations, gives (typically) the number of bytes per operation. No Display Suffix.";
case PERF_OBJ_TIME_TIMER:
return "64-bit Timer in object specific units. Display delta divided by delta time as returned in the object type header structure. Display suffix: \"%\"";
case PERF_100NSEC_TIMER:
return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\"";
case PERF_100NSEC_TIMER_INV:
return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
case PERF_COUNTER_MULTI_TIMER:
return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\". Timer for multiple instances, so result can exceed 100%.";
case PERF_COUNTER_MULTI_TIMER_INV:
return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
case PERF_COUNTER_MULTI_BASE:
return "Number of instances to which the preceding _MULTI_..._INV counter applies. Used as a factor to get the percentage.";
case PERF_100NSEC_MULTI_TIMER:
return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%.";
case PERF_100NSEC_MULTI_TIMER_INV:
return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
case PERF_LARGE_RAW_FRACTION:
case PERF_RAW_FRACTION:
return "Indicates the data is a fraction of the following counter which should not be time averaged on display (such as free space over total space.) Display as is. Display the quotient as \"%\"";
case PERF_RAW_BASE:
case PERF_LARGE_RAW_BASE:
return "Indicates the data is a base for the preceding counter which should not be time averaged on display (such as free space over total space.)";
case PERF_ELAPSED_TIME:
return "The data collected in this counter is actually the start time of the item being measured. For display, this data is subtracted from the sample time to yield the elapsed time as the difference between the two. In the definition below, the PerfTime field of the Object contains the sample time as indicated by the PERF_OBJECT_TIMER bit and the difference is scaled by the PerfFreq of the Object to convert the time units into seconds.";
case PERF_COUNTER_HISTOGRAM_TYPE:
return "Counter type can be used with the preceding types to define a range of values to be displayed in a histogram.";
case PERF_COUNTER_DELTA:
case PERF_COUNTER_LARGE_DELTA:
return "This counter is used to display the difference from one sample to the next. The counter value is a constantly increasing number and the value displayed is the difference between the current value and the previous value. Negative numbers are not allowed which shouldn't be a problem as long as the counter value is increasing or unchanged.";
case PERF_PRECISION_SYSTEM_TIMER:
return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the System Performance Timer";
case PERF_PRECISION_100NS_TIMER:
return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the 100 NanoSecond Timer";
case PERF_PRECISION_OBJECT_TIMER:
return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used is of the frequency specified in the Object header's. PerfFreq field (PerfTime is ignored)";
default:
return "";
}
}
static const char *getCounterAlgorithm(DWORD CounterType) {
switch (CounterType)
{
case PERF_COUNTER_COUNTER:
case PERF_SAMPLE_COUNTER:
case PERF_COUNTER_BULK_COUNT:
return "(data1 - data0) / ((time1 - time0) / frequency)";
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
case PERF_AVERAGE_BULK: // normally not displayed
return "(data1 - data0) / (time1 - time0)";
case PERF_OBJ_TIME_TIMER:
case PERF_COUNTER_TIMER:
case PERF_100NSEC_TIMER:
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
case PERF_SAMPLE_FRACTION:
return "100 * (data1 - data0) / (time1 - time0)";
case PERF_COUNTER_TIMER_INV:
return "100 * (1 - ((data1 - data0) / (time1 - time0)))";
case PERF_100NSEC_TIMER_INV:
return "100 * (1- (data1 - data0) / (time1 - time0))";
case PERF_COUNTER_MULTI_TIMER:
return "100 * ((data1 - data0) / ((time1 - time0) / frequency1)) / multi1";
case PERF_100NSEC_MULTI_TIMER:
return "100 * ((data1 - data0) / (time1 - time0)) / multi1";
case PERF_COUNTER_MULTI_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER_INV:
return "100 * (multi1 - ((data1 - data0) / (time1 - time0)))";
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT:
return "data0";
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
return "hex(data0)";
case PERF_COUNTER_DELTA:
case PERF_COUNTER_LARGE_DELTA:
return "data1 - data0";
case PERF_RAW_FRACTION:
case PERF_LARGE_RAW_FRACTION:
return "100 * data0 / time0";
case PERF_AVERAGE_TIMER:
return "((data1 - data0) / frequency1) / (time1 - time0)";
case PERF_ELAPSED_TIME:
return "(time0 - data0) / frequency0";
case PERF_COUNTER_TEXT:
case PERF_SAMPLE_BASE:
case PERF_AVERAGE_BASE:
case PERF_COUNTER_MULTI_BASE:
case PERF_RAW_BASE:
case PERF_COUNTER_NODATA:
case PERF_PRECISION_TIMESTAMP:
default:
return "";
}
}
void dumpSystemTime(BUFFER *wb, SYSTEMTIME *st) {
buffer_json_member_add_uint64(wb, "Year", st->wYear);
buffer_json_member_add_uint64(wb, "Month", st->wMonth);
buffer_json_member_add_uint64(wb, "DayOfWeek", st->wDayOfWeek);
buffer_json_member_add_uint64(wb, "Day", st->wDay);
buffer_json_member_add_uint64(wb, "Hour", st->wHour);
buffer_json_member_add_uint64(wb, "Minute", st->wMinute);
buffer_json_member_add_uint64(wb, "Second", st->wSecond);
buffer_json_member_add_uint64(wb, "Milliseconds", st->wMilliseconds);
}
bool dumpDataCb(PERF_DATA_BLOCK *pDataBlock, void *data) {
char name[4096];
if(!getSystemName(pDataBlock, name, sizeof(name)))
strncpyz(name, "[failed]", sizeof(name) - 1);
BUFFER *wb = data;
buffer_json_member_add_string(wb, "SystemName", name);
// Number of types of objects being reported
// Type: DWORD
buffer_json_member_add_int64(wb, "NumObjectTypes", pDataBlock->NumObjectTypes);
buffer_json_member_add_int64(wb, "LittleEndian", pDataBlock->LittleEndian);
// Version and Revision of these data structures.
// Version starts at 1.
// Revision starts at 0 for each Version.
// Type: DWORD
buffer_json_member_add_int64(wb, "Version", pDataBlock->Version);
buffer_json_member_add_int64(wb, "Revision", pDataBlock->Revision);
// Object Title Index of default object to display when data from this system is retrieved
// (-1 = none, but this is not expected to be used)
// Type: LONG
buffer_json_member_add_int64(wb, "DefaultObject", pDataBlock->DefaultObject);
// Performance counter frequency at the system under measurement
// Type: LARGE_INTEGER
buffer_json_member_add_int64(wb, "PerfFreq", pDataBlock->PerfFreq.QuadPart);
// Performance counter value at the system under measurement
// Type: LARGE_INTEGER
buffer_json_member_add_int64(wb, "PerfTime", pDataBlock->PerfTime.QuadPart);
// Performance counter time in 100 nsec units at the system under measurement
// Type: LARGE_INTEGER
buffer_json_member_add_int64(wb, "PerfTime100nSec", pDataBlock->PerfTime100nSec.QuadPart);
// Time at the system under measurement in UTC
// Type: SYSTEMTIME
buffer_json_member_add_object(wb, "SystemTime");
dumpSystemTime(wb, &pDataBlock->SystemTime);
buffer_json_object_close(wb);
if(pDataBlock->NumObjectTypes)
buffer_json_member_add_array(wb, "Objects");
return true;
}
static const char *GetDetailLevel(DWORD num) {
switch (num) {
case 100:
return "Novice (100)";
case 200:
return "Advanced (200)";
case 300:
return "Expert (300)";
case 400:
return "Wizard (400)";
default:
return "Unknown";
}
}
bool dumpObjectCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, void *data) {
(void)pDataBlock;
BUFFER *wb = data;
if(!pObjectType) {
buffer_json_array_close(wb); // instances or counters
buffer_json_object_close(wb); // objectType
return true;
}
buffer_json_add_array_item_object(wb); // objectType
buffer_json_member_add_int64(wb, "NameId", pObjectType->ObjectNameTitleIndex);
buffer_json_member_add_string(wb, "Name", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
buffer_json_member_add_int64(wb, "HelpId", pObjectType->ObjectHelpTitleIndex);
buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pObjectType->ObjectHelpTitleIndex));
buffer_json_member_add_int64(wb, "NumInstances", pObjectType->NumInstances);
buffer_json_member_add_int64(wb, "NumCounters", pObjectType->NumCounters);
buffer_json_member_add_int64(wb, "PerfTime", pObjectType->PerfTime.QuadPart);
buffer_json_member_add_int64(wb, "PerfFreq", pObjectType->PerfFreq.QuadPart);
buffer_json_member_add_int64(wb, "CodePage", pObjectType->CodePage);
buffer_json_member_add_int64(wb, "DefaultCounter", pObjectType->DefaultCounter);
buffer_json_member_add_string(wb, "DetailLevel", GetDetailLevel(pObjectType->DetailLevel));
if(ObjectTypeHasInstances(pDataBlock, pObjectType))
buffer_json_member_add_array(wb, "Instances");
else
buffer_json_member_add_array(wb, "Counters");
return true;
}
bool dumpInstanceCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, void *data) {
(void)pDataBlock;
BUFFER *wb = data;
if(!pInstance) {
buffer_json_array_close(wb); // counters
buffer_json_object_close(wb); // instance
return true;
}
char name[4096];
if(!getInstanceName(pDataBlock, pObjectType, pInstance, name, sizeof(name)))
strncpyz(name, "[failed]", sizeof(name) - 1);
buffer_json_add_array_item_object(wb);
buffer_json_member_add_string(wb, "Instance", name);
buffer_json_member_add_int64(wb, "UniqueID", pInstance->UniqueID);
buffer_json_member_add_array(wb, "Labels");
{
buffer_json_add_array_item_object(wb);
{
buffer_json_member_add_string(wb, "key", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
buffer_json_member_add_string(wb, "value", name);
}
buffer_json_object_close(wb);
if(pInstance->ParentObjectTitleIndex) {
PERF_INSTANCE_DEFINITION *pi = pInstance;
while(pi->ParentObjectTitleIndex) {
PERF_OBJECT_TYPE *po = getObjectTypeByIndex(pDataBlock, pInstance->ParentObjectTitleIndex);
pi = getInstanceByPosition(pDataBlock, po, pi->ParentObjectInstance);
if(!getInstanceName(pDataBlock, po, pi, name, sizeof(name)))
strncpyz(name, "[failed]", sizeof(name) - 1);
buffer_json_add_array_item_object(wb);
{
buffer_json_member_add_string(wb, "key", RegistryFindNameByID(po->ObjectNameTitleIndex));
buffer_json_member_add_string(wb, "value", name);
}
buffer_json_object_close(wb);
}
}
}
buffer_json_array_close(wb); // rrdlabels
buffer_json_member_add_array(wb, "Counters");
return true;
}
void dumpSample(BUFFER *wb, RAW_DATA *d) {
buffer_json_member_add_object(wb, "Value");
buffer_json_member_add_uint64(wb, "data", d->Data);
buffer_json_member_add_int64(wb, "time", d->Time);
buffer_json_member_add_uint64(wb, "type", d->CounterType);
buffer_json_member_add_int64(wb, "multi", d->MultiCounterData);
buffer_json_member_add_int64(wb, "frequency", d->Frequency);
buffer_json_object_close(wb);
}
bool dumpCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
(void)pDataBlock;
(void)pObjectType;
BUFFER *wb = data;
buffer_json_add_array_item_object(wb);
buffer_json_member_add_string(wb, "Counter", RegistryFindNameByID(pCounter->CounterNameTitleIndex));
dumpSample(wb, sample);
buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pCounter->CounterHelpTitleIndex));
buffer_json_member_add_string(wb, "Type", getCounterType(pCounter->CounterType));
buffer_json_member_add_string(wb, "Algorithm", getCounterAlgorithm(pCounter->CounterType));
buffer_json_member_add_string(wb, "Description", getCounterDescription(pCounter->CounterType));
buffer_json_object_close(wb);
return true;
}
bool dumpInstanceCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
(void)pInstance;
return dumpCounterCb(pDataBlock, pObjectType, pCounter, sample, data);
}
int windows_perflib_dump(const char *key) {
if(key && !*key)
key = NULL;
PerflibNamesRegistryInitialize();
DWORD id = 0;
if(key) {
id = RegistryFindIDByName(key);
if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
fprintf(stderr, "Cannot find key '%s' in Windows Performance Counters Registry.\n", key);
exit(1);
}
}
CLEAN_BUFFER *wb = buffer_create(0, NULL);
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
perflibQueryAndTraverse(id, dumpDataCb, dumpObjectCb, dumpInstanceCb, dumpInstanceCounterCb, dumpCounterCb, wb);
buffer_json_finalize(wb);
printf("\n%s\n", buffer_tostring(wb));
perflibFreePerformanceData();
return 0;
}

View file

@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
#define _COMMON_PLUGIN_NAME "windows.plugin"
#define _COMMON_PLUGIN_MODULE_NAME "PerflibMemory"
#include "../common-contexts/common-contexts.h"
static void initialize(void) {
;
}
static bool do_memory(PERF_DATA_BLOCK *pDataBlock, int update_every) {
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Memory");
if (!pObjectType)
return false;
static COUNTER_DATA pagesPerSec = { .key = "Pages/sec" };
static COUNTER_DATA pageFaultsPerSec = { .key = "Page Faults/sec" };
if(perflibGetObjectCounter(pDataBlock, pObjectType, &pageFaultsPerSec) &&
perflibGetObjectCounter(pDataBlock, pObjectType, &pagesPerSec)) {
ULONGLONG total = pageFaultsPerSec.current.Data;
ULONGLONG major = pagesPerSec.current.Data;
ULONGLONG minor = (total > major) ? total - major : 0;
common_mem_pgfaults(minor, major, update_every);
}
static COUNTER_DATA availableBytes = { .key = "Available Bytes" };
static COUNTER_DATA availableKBytes = { .key = "Available KBytes" };
static COUNTER_DATA availableMBytes = { .key = "Available MBytes" };
ULONGLONG available_bytes = 0;
if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableBytes))
available_bytes = availableBytes.current.Data;
else if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableKBytes))
available_bytes = availableKBytes.current.Data * 1024;
else if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableMBytes))
available_bytes = availableMBytes.current.Data * 1024;
common_mem_available(available_bytes, update_every);
return true;
}
int do_PerflibMemory(int update_every, usec_t dt __maybe_unused) {
static bool initialized = false;
if(unlikely(!initialized)) {
initialize();
initialized = true;
}
DWORD id = RegistryFindIDByName("Memory");
if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
return -1;
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
if(!pDataBlock) return -1;
do_memory(pDataBlock, update_every);
return 0;
}

View file

@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "perflib.h"
#define REGISTRY_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
typedef struct perflib_registry {
DWORD id;
char *key;
char *help;
} perfLibRegistryEntry;
static inline bool compare_perfLibRegistryEntry(const char *k1, const char *k2) {
return strcmp(k1, k2) == 0;
}
static inline const char *value2key_perfLibRegistryEntry(perfLibRegistryEntry *entry) {
return entry->key;
}
#define SIMPLE_HASHTABLE_COMPARE_KEYS_FUNCTION compare_perfLibRegistryEntry
#define SIMPLE_HASHTABLE_VALUE2KEY_FUNCTION value2key_perfLibRegistryEntry
#define SIMPLE_HASHTABLE_KEY_TYPE const char
#define SIMPLE_HASHTABLE_VALUE_TYPE perfLibRegistryEntry
#define SIMPLE_HASHTABLE_NAME _PERFLIB
#include "libnetdata/simple_hashtable.h"
static struct {
SPINLOCK spinlock;
size_t size;
perfLibRegistryEntry **array;
struct simple_hashtable_PERFLIB hashtable;
FILETIME lastWriteTime;
} names_globals = {
.spinlock = NETDATA_SPINLOCK_INITIALIZER,
.size = 0,
.array = NULL,
};
DWORD RegistryFindIDByName(const char *name) {
DWORD rc = PERFLIB_REGISTRY_NAME_NOT_FOUND;
spinlock_lock(&names_globals.spinlock);
XXH64_hash_t hash = XXH3_64bits((void *)name, strlen(name));
SIMPLE_HASHTABLE_SLOT_PERFLIB *sl = simple_hashtable_get_slot_PERFLIB(&names_globals.hashtable, hash, name, false);
perfLibRegistryEntry *e = SIMPLE_HASHTABLE_SLOT_DATA(sl);
if(e) rc = e->id;
spinlock_unlock(&names_globals.spinlock);
return rc;
}
static inline void RegistryAddToHashTable_unsafe(perfLibRegistryEntry *entry) {
XXH64_hash_t hash = XXH3_64bits((void *)entry->key, strlen(entry->key));
SIMPLE_HASHTABLE_SLOT_PERFLIB *sl = simple_hashtable_get_slot_PERFLIB(&names_globals.hashtable, hash, entry->key, true);
perfLibRegistryEntry *e = SIMPLE_HASHTABLE_SLOT_DATA(sl);
if(!e || e->id > entry->id)
simple_hashtable_set_slot_PERFLIB(&names_globals.hashtable, sl, hash, entry);
}
static void RegistrySetData_unsafe(DWORD id, const char *key, const char *help) {
if(id >= names_globals.size) {
// increase the size of the array
size_t old_size = names_globals.size;
if(!names_globals.size)
names_globals.size = 20000;
else
names_globals.size *= 2;
names_globals.array = reallocz(names_globals.array, names_globals.size * sizeof(perfLibRegistryEntry *));
memset(names_globals.array + old_size, 0, (names_globals.size - old_size) * sizeof(perfLibRegistryEntry *));
}
perfLibRegistryEntry *entry = names_globals.array[id];
if(!entry)
entry = names_globals.array[id] = (perfLibRegistryEntry *)calloc(1, sizeof(perfLibRegistryEntry));
bool add_to_hash = false;
if(key && !entry->key) {
entry->key = strdup(key);
add_to_hash = true;
}
if(help && !entry->help)
entry->help = strdup(help);
entry->id = id;
if(add_to_hash)
RegistryAddToHashTable_unsafe(entry);
}
const char *RegistryFindNameByID(DWORD id) {
const char *s = "";
spinlock_lock(&names_globals.spinlock);
if(id < names_globals.size) {
perfLibRegistryEntry *titleEntry = names_globals.array[id];
if(titleEntry && titleEntry->key)
s = titleEntry->key;
}
spinlock_unlock(&names_globals.spinlock);
return s;
}
const char *RegistryFindHelpByID(DWORD id) {
const char *s = "";
spinlock_lock(&names_globals.spinlock);
if(id < names_globals.size) {
perfLibRegistryEntry *titleEntry = names_globals.array[id];
if(titleEntry && titleEntry->help)
s = titleEntry->help;
}
spinlock_unlock(&names_globals.spinlock);
return s;
}
// ----------------------------------------------------------
static inline void readRegistryKeys_unsafe(BOOL helps) {
TCHAR *pData = NULL;
HKEY hKey;
DWORD dwType;
DWORD dwSize = 0;
LONG lStatus;
LPCSTR valueName;
if(helps)
valueName = TEXT("help");
else
valueName = TEXT("CounterDefinition");
// Open the key for the English counters
lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGISTRY_KEY), 0, KEY_READ, &hKey);
if (lStatus != ERROR_SUCCESS) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"Failed to open registry key HKEY_LOCAL_MACHINE, subkey '%s', error %ld\n", REGISTRY_KEY, (long)lStatus);
return;
}
// Get the size of the 'Counters' data
lStatus = RegQueryValueEx(hKey, valueName, NULL, &dwType, NULL, &dwSize);
if (lStatus != ERROR_SUCCESS) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"Failed to get registry key HKEY_LOCAL_MACHINE, subkey '%s', value '%s', size of data, error %ld\n",
REGISTRY_KEY, (const char *)valueName, (long)lStatus);
goto cleanup;
}
// Allocate memory for the data
pData = mallocz(dwSize);
// Read the 'Counters' data
lStatus = RegQueryValueEx(hKey, valueName, NULL, &dwType, (LPBYTE)pData, &dwSize);
if (lStatus != ERROR_SUCCESS || dwType != REG_MULTI_SZ) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"Failed to get registry key HKEY_LOCAL_MACHINE, subkey '%s', value '%s', data, error %ld\n",
REGISTRY_KEY, (const char *)valueName, (long)lStatus);
goto cleanup;
}
// Process the counter data
TCHAR *ptr = pData;
while (*ptr) {
TCHAR *sid = ptr; // First string is the ID
ptr += lstrlen(ptr) + 1; // Move to the next string
TCHAR *name = ptr; // Second string is the name
ptr += lstrlen(ptr) + 1; // Move to the next pair
DWORD id = strtoul(sid, NULL, 10);
if(helps)
RegistrySetData_unsafe(id, NULL, name);
else
RegistrySetData_unsafe(id, name, NULL);
}
cleanup:
if(pData) freez(pData);
RegCloseKey(hKey);
}
static BOOL RegistryKeyModification(FILETIME *lastWriteTime) {
HKEY hKey;
LONG lResult;
BOOL ret = FALSE;
// Open the registry key
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGISTRY_KEY), 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"Failed to open registry key HKEY_LOCAL_MACHINE, subkey '%s', error %ld\n", REGISTRY_KEY, (long)lResult);
return FALSE;
}
// Get the last write time
lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, lastWriteTime);
if (lResult != ERROR_SUCCESS) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"Failed to query registry key HKEY_LOCAL_MACHINE, subkey '%s', last write time, error %ld\n", REGISTRY_KEY, (long)lResult);
ret = FALSE;
}
else
ret = TRUE;
RegCloseKey(hKey);
return ret;
}
static inline void RegistryFetchAll_unsafe(void) {
readRegistryKeys_unsafe(FALSE);
readRegistryKeys_unsafe(TRUE);
}
void PerflibNamesRegistryInitialize(void) {
spinlock_lock(&names_globals.spinlock);
simple_hashtable_init_PERFLIB(&names_globals.hashtable, 20000);
RegistryKeyModification(&names_globals.lastWriteTime);
RegistryFetchAll_unsafe();
spinlock_unlock(&names_globals.spinlock);
}
void PerflibNamesRegistryUpdate(void) {
FILETIME lastWriteTime = { 0 };
RegistryKeyModification(&lastWriteTime);
if(CompareFileTime(&lastWriteTime, &names_globals.lastWriteTime) > 0) {
spinlock_lock(&names_globals.spinlock);
if(CompareFileTime(&lastWriteTime, &names_globals.lastWriteTime) > 0) {
names_globals.lastWriteTime = lastWriteTime;
RegistryFetchAll_unsafe();
}
spinlock_unlock(&names_globals.spinlock);
}
}

View file

@ -0,0 +1,453 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
// --------------------------------------------------------------------------------------------------------------------
// network protocols
struct network_protocol {
const char *protocol;
struct {
COUNTER_DATA received;
COUNTER_DATA sent;
COUNTER_DATA delivered;
COUNTER_DATA forwarded;
RRDSET *st;
RRDDIM *rd_received;
RRDDIM *rd_sent;
RRDDIM *rd_forwarded;
RRDDIM *rd_delivered;
const char *type;
const char *id;
const char *family;
const char *context;
const char *title;
long priority;
} packets;
} networks[] = {
{
.protocol = "IPv4",
.packets = {
.received = { .key = "Datagrams Received/sec" },
.sent = { .key = "Datagrams Sent/sec" },
.delivered = { .key = "Datagrams Received Delivered/sec" },
.forwarded = { .key = "Datagrams Forwarded/sec" },
.type = "ipv4",
.id = "packets",
.family = "packets",
.context = "ipv4.packets",
.title = "IPv4 Packets",
.priority = NETDATA_CHART_PRIO_IPV4_PACKETS,
},
},
{
.protocol = "IPv6",
.packets = {
.received = { .key = "Datagrams Received/sec" },
.sent = { .key = "Datagrams Sent/sec" },
.delivered = { .key = "Datagrams Received Delivered/sec" },
.forwarded = { .key = "Datagrams Forwarded/sec" },
.type = "ipv6",
.id = "packets",
.family = "packets",
.context = "ip6.packets",
.title = "IPv6 Packets",
.priority = NETDATA_CHART_PRIO_IPV6_PACKETS,
},
},
{
.protocol = "TCPv4",
.packets = {
.received = { .key = "Segments Received/sec" },
.sent = { .key = "Segments Sent/sec" },
.type = "ipv4",
.id = "tcppackets",
.family = "tcp",
.context = "ipv4.tcppackets",
.title = "IPv4 TCP Packets",
.priority = NETDATA_CHART_PRIO_IPV4_TCP_PACKETS,
},
},
{
.protocol = "TCPv6",
.packets = {
.received = { .key = "Segments Received/sec" },
.sent = { .key = "Segments Sent/sec" },
.type = "ipv6",
.id = "tcppackets",
.family = "tcp6",
.context = "ipv6.tcppackets",
.title = "IPv6 TCP Packets",
.priority = NETDATA_CHART_PRIO_IPV6_TCP_PACKETS,
},
},
{
.protocol = "UDPv4",
.packets = {
.received = { .key = "Datagrams Received/sec" },
.sent = { .key = "Datagrams Sent/sec" },
.type = "ipv4",
.id = "udppackets",
.family = "udp",
.context = "ipv4.udppackets",
.title = "IPv4 UDP Packets",
.priority = NETDATA_CHART_PRIO_IPV4_UDP_PACKETS,
},
},
{
.protocol = "UDPv6",
.packets = {
.received = { .key = "Datagrams Received/sec" },
.sent = { .key = "Datagrams Sent/sec" },
.type = "ipv6",
.id = "udppackets",
.family = "udp6",
.context = "ipv6.udppackets",
.title = "IPv6 UDP Packets",
.priority = NETDATA_CHART_PRIO_IPV6_UDP_PACKETS,
},
},
{
.protocol = "ICMP",
.packets = {
.received = { .key = "Messages Received/sec" },
.sent = { .key = "Messages Sent/sec" },
.type = "ipv4",
.id = "icmp",
.family = "icmp",
.context = "ipv4.icmp",
.title = "IPv4 ICMP Packets",
.priority = NETDATA_CHART_PRIO_IPV4_ICMP_PACKETS,
},
},
{
.protocol = "ICMPv6",
.packets = {
.received = { .key = "Messages Received/sec" },
.sent = { .key = "Messages Sent/sec" },
.type = "ipv6",
.id = "icmp",
.family = "icmp6",
.context = "ipv6.icmp",
.title = "IPv6 ICMP Packets",
.priority = NETDATA_CHART_PRIO_IPV6_ICMP_PACKETS,
},
},
// terminator
{
.protocol = NULL,
}
};
struct network_protocol tcp46 = {
.packets = {
.type = "ip",
.id = "tcppackets",
.family = "tcp",
.context = "ip.tcppackets",
.title = "TCP Packets",
.priority = NETDATA_CHART_PRIO_IP_TCP_PACKETS,
}
};
static void protocol_packets_chart_update(struct network_protocol *p, int update_every) {
if(!p->packets.st) {
p->packets.st = rrdset_create_localhost(
p->packets.type
, p->packets.id
, NULL
, p->packets.family
, NULL
, p->packets.title
, "packets/s"
, PLUGIN_WINDOWS_NAME
, "PerflibNetwork"
, p->packets.priority
, update_every
, RRDSET_TYPE_AREA
);
p->packets.rd_received = rrddim_add(p->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
p->packets.rd_sent = rrddim_add(p->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
if(p->packets.forwarded.key)
p->packets.rd_forwarded = rrddim_add(p->packets.st, "forwarded", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
if(p->packets.delivered.key)
p->packets.rd_delivered = rrddim_add(p->packets.st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
}
if(p->packets.received.updated)
rrddim_set_by_pointer(p->packets.st, p->packets.rd_received, (collected_number)p->packets.received.current.Data);
if(p->packets.sent.updated)
rrddim_set_by_pointer(p->packets.st, p->packets.rd_sent, (collected_number)p->packets.sent.current.Data);
if(p->packets.forwarded.key && p->packets.forwarded.updated)
rrddim_set_by_pointer(p->packets.st, p->packets.rd_forwarded, (collected_number)p->packets.forwarded.current.Data);
if(p->packets.delivered.key && p->packets.delivered.updated)
rrddim_set_by_pointer(p->packets.st, p->packets.rd_delivered, (collected_number)p->packets.delivered.current.Data);
rrdset_done(p->packets.st);
}
static bool do_network_protocol(PERF_DATA_BLOCK *pDataBlock, int update_every, struct network_protocol *p) {
if(!p || !p->protocol) return false;
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->protocol);
if(!pObjectType) return false;
size_t packets = 0;
if(p->packets.received.key)
packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.received) ? 1 : 0;
if(p->packets.sent.key)
packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.sent) ? 1 : 0;
if(p->packets.delivered.key)
packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.delivered) ? 1 :0;
if(p->packets.forwarded.key)
packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.forwarded) ? 1 : 0;
if(packets)
protocol_packets_chart_update(p, update_every);
return true;
}
// --------------------------------------------------------------------------------------------------------------------
// network interfaces
struct network_interface {
bool collected_metadata;
struct {
COUNTER_DATA received;
COUNTER_DATA sent;
RRDSET *st;
RRDDIM *rd_received;
RRDDIM *rd_sent;
} packets;
struct {
COUNTER_DATA received;
COUNTER_DATA sent;
RRDSET *st;
RRDDIM *rd_received;
RRDDIM *rd_sent;
} traffic;
};
static DICTIONARY *physical_interfaces = NULL, *virtual_interfaces = NULL;
static void network_interface_init(struct network_interface *ni) {
ni->packets.received.key = "Packets Received/sec";
ni->packets.sent.key = "Packets Sent/sec";
ni->traffic.received.key = "Bytes Received/sec";
ni->traffic.sent.key = "Bytes Sent/sec";
}
void dict_interface_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
struct network_interface *ni = value;
network_interface_init(ni);
}
static void initialize(void) {
physical_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
virtual_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
dictionary_register_insert_callback(physical_interfaces, dict_interface_insert_cb, NULL);
dictionary_register_insert_callback(virtual_interfaces, dict_interface_insert_cb, NULL);
}
static void add_interface_labels(RRDSET *st, const char *name, bool physical) {
rrdlabels_add(st->rrdlabels, "device", name, RRDLABEL_SRC_AUTO);
rrdlabels_add(st->rrdlabels, "interface_type", physical ? "real" : "virtual", RRDLABEL_SRC_AUTO);
}
static bool is_physical_interface(const char *name) {
void *d = dictionary_get(physical_interfaces, name);
return d ? true : false;
}
static bool do_network_interface(PERF_DATA_BLOCK *pDataBlock, int update_every, bool physical) {
DICTIONARY *dict = physical_interfaces;
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, physical ? "Network Interface" : "Network Adapter");
if(!pObjectType) return false;
uint64_t total_received = 0, total_sent = 0;
PERF_INSTANCE_DEFINITION *pi = NULL;
for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
if(!pi) break;
if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
if(strcasecmp(windows_shared_buffer, "_Total") == 0)
continue;
if(!physical && is_physical_interface(windows_shared_buffer))
// this virtual interface is already reported as physical interface
continue;
struct network_interface *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
if(!d->collected_metadata) {
// TODO - get metadata about the network interface
d->collected_metadata = true;
}
if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.received) ||
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.sent)) {
if(d->traffic.received.current.Data == 0 && d->traffic.sent.current.Data == 0)
// this interface has not received or sent any traffic
continue;
if (unlikely(!d->traffic.st)) {
d->traffic.st = rrdset_create_localhost(
"net",
windows_shared_buffer,
NULL,
windows_shared_buffer,
"net.net",
"Bandwidth",
"kilobits/s",
PLUGIN_WINDOWS_NAME,
"PerflibNetwork",
NETDATA_CHART_PRIO_FIRST_NET_IFACE,
update_every,
RRDSET_TYPE_AREA);
rrdset_flag_set(d->traffic.st, RRDSET_FLAG_DETAIL);
add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
d->traffic.rd_received = rrddim_add(d->traffic.st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
d->traffic.rd_sent = rrddim_add(d->traffic.st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
total_received += d->traffic.received.current.Data;
total_sent += d->traffic.sent.current.Data;
rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_received, (collected_number)d->traffic.received.current.Data);
rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_sent, (collected_number)d->traffic.sent.current.Data);
rrdset_done(d->traffic.st);
}
if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.received) ||
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.sent)) {
if (unlikely(!d->packets.st)) {
d->packets.st = rrdset_create_localhost(
"net_packets",
windows_shared_buffer,
NULL,
windows_shared_buffer,
"net.packets",
"Packets",
"packets/s",
PLUGIN_WINDOWS_NAME,
"PerflibNetwork",
NETDATA_CHART_PRIO_FIRST_NET_IFACE + 1,
update_every,
RRDSET_TYPE_LINE);
rrdset_flag_set(d->packets.st, RRDSET_FLAG_DETAIL);
add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
d->packets.rd_received = rrddim_add(d->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->packets.rd_sent = rrddim_add(d->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(d->packets.st, d->packets.rd_received, (collected_number)d->packets.received.current.Data);
rrddim_set_by_pointer(d->packets.st, d->packets.rd_sent, (collected_number)d->packets.sent.current.Data);
rrdset_done(d->packets.st);
}
}
if(physical) {
static RRDSET *st = NULL;
static RRDDIM *rd_received = NULL, *rd_sent = NULL;
if (unlikely(!st)) {
st = rrdset_create_localhost(
"system",
"net",
NULL,
"network",
"system.net",
"Physical Network Interfaces Aggregated Bandwidth",
"kilobits/s",
PLUGIN_WINDOWS_NAME,
"PerflibNetwork",
NETDATA_CHART_PRIO_SYSTEM_NET,
update_every,
RRDSET_TYPE_AREA);
rd_received = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
rd_sent = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
}
rrddim_set_by_pointer(st, rd_received, (collected_number)total_received);
rrddim_set_by_pointer(st, rd_sent, (collected_number)total_sent);
rrdset_done(st);
}
return true;
}
int do_PerflibNetwork(int update_every, usec_t dt __maybe_unused) {
static bool initialized = false;
if(unlikely(!initialized)) {
initialize();
initialized = true;
}
DWORD id = RegistryFindIDByName("Network Interface");
if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
return -1;
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
if(!pDataBlock) return -1;
do_network_interface(pDataBlock, update_every, true);
do_network_interface(pDataBlock, update_every, false);
struct network_protocol *tcp4 = NULL, *tcp6 = NULL;
for(size_t i = 0; networks[i].protocol ;i++) {
do_network_protocol(pDataBlock, update_every, &networks[i]);
if(!tcp4 && strcmp(networks[i].protocol, "TCPv4") == 0)
tcp4 = &networks[i];
if(!tcp6 && strcmp(networks[i].protocol, "TCPv6") == 0)
tcp6 = &networks[i];
}
if(tcp4 && tcp6) {
tcp46.packets.received = tcp4->packets.received;
tcp46.packets.sent = tcp4->packets.sent;
tcp46.packets.received.current.Data += tcp6->packets.received.current.Data;
tcp46.packets.sent.current.Data += tcp6->packets.sent.current.Data;
protocol_packets_chart_update(&tcp46, update_every);
}
return 0;
}

View file

@ -0,0 +1,191 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
struct processor {
bool collected_metadata;
RRDSET *st;
RRDDIM *rd_user;
RRDDIM *rd_system;
RRDDIM *rd_irq;
RRDDIM *rd_dpc;
RRDDIM *rd_idle;
// RRDSET *st2;
// RRDDIM *rd2_busy;
COUNTER_DATA percentProcessorTime;
COUNTER_DATA percentUserTime;
COUNTER_DATA percentPrivilegedTime;
COUNTER_DATA percentDPCTime;
COUNTER_DATA percentInterruptTime;
COUNTER_DATA percentIdleTime;
};
struct processor total = { 0 };
void initialize_processor_keys(struct processor *p) {
p->percentProcessorTime.key = "% Processor Time";
p->percentUserTime.key = "% User Time";
p->percentPrivilegedTime.key = "% Privileged Time";
p->percentDPCTime.key = "% DPC Time";
p->percentInterruptTime.key = "% Interrupt Time";
p->percentIdleTime.key = "% Idle Time";
}
void dict_processor_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
struct processor *p = value;
initialize_processor_keys(p);
}
static DICTIONARY *processors = NULL;
static void initialize(void) {
initialize_processor_keys(&total);
processors = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct processor));
dictionary_register_insert_callback(processors, dict_processor_insert_cb, NULL);
}
static bool do_processors(PERF_DATA_BLOCK *pDataBlock, int update_every) {
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Processor");
if(!pObjectType) return false;
static const RRDVAR_ACQUIRED *cpus_var = NULL;
int cores_found = 0;
PERF_INSTANCE_DEFINITION *pi = NULL;
for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
if(!pi) break;
if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
bool is_total = false;
struct processor *p;
int cpu = -1;
if(strcasecmp(windows_shared_buffer, "_Total") == 0) {
p = &total;
is_total = true;
cpu = -1;
}
else {
p = dictionary_set(processors, windows_shared_buffer, NULL, sizeof(*p));
is_total = false;
cpu = str2i(windows_shared_buffer);
snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "cpu%d", cpu);
if(cpu + 1 > cores_found)
cores_found = cpu + 1;
}
if(!is_total && !p->collected_metadata) {
// TODO collect processor metadata
p->collected_metadata = true;
}
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentProcessorTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentUserTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentPrivilegedTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentDPCTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentInterruptTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentIdleTime);
if(!p->st) {
p->st = rrdset_create_localhost(
is_total ? "system" : "cpu"
, is_total ? "cpu" : windows_shared_buffer, NULL
, is_total ? "cpu" : "utilization"
, is_total ? "system.cpu" : "cpu.cpu"
, is_total ? "Total CPU Utilization" : "Core Utilization"
, "percentage"
, PLUGIN_WINDOWS_NAME
, "PerflibProcessor"
, is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE
, update_every
, RRDSET_TYPE_STACKED
);
p->rd_irq = rrddim_add(p->st, "interrupts", "irq", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
p->rd_user = rrddim_add(p->st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
p->rd_system = rrddim_add(p->st, "privileged", "system", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
p->rd_dpc = rrddim_add(p->st, "dpc", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
p->rd_idle = rrddim_add(p->st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
rrddim_hide(p->st, "idle");
if(!is_total)
rrdlabels_add(p->st->rrdlabels, "cpu", windows_shared_buffer, RRDLABEL_SRC_AUTO);
else
cpus_var = rrdvar_host_variable_add_and_acquire(localhost, "active_processors");
}
uint64_t user = p->percentUserTime.current.Data;
uint64_t system = p->percentPrivilegedTime.current.Data;
uint64_t dpc = p->percentDPCTime.current.Data;
uint64_t irq = p->percentInterruptTime.current.Data;
uint64_t idle = p->percentIdleTime.current.Data;
rrddim_set_by_pointer(p->st, p->rd_user, (collected_number)user);
rrddim_set_by_pointer(p->st, p->rd_system, (collected_number)system);
rrddim_set_by_pointer(p->st, p->rd_irq, (collected_number)irq);
rrddim_set_by_pointer(p->st, p->rd_dpc, (collected_number)dpc);
rrddim_set_by_pointer(p->st, p->rd_idle, (collected_number)idle);
rrdset_done(p->st);
// if(!p->st2) {
// p->st2 = rrdset_create_localhost(
// is_total ? "system" : "cpu2"
// , is_total ? "cpu3" : buffer
// , NULL
// , is_total ? "utilization" : buffer
// , is_total ? "system.cpu3" : "cpu2.cpu"
// , is_total ? "Total CPU Utilization" : "Core Utilization"
// , "percentage"
// , PLUGIN_WINDOWS_NAME
// , "PerflibProcessor"
// , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE
// , update_every
// , RRDSET_TYPE_STACKED
// );
//
// p->rd2_busy = perflib_rrddim_add(p->st2, "busy", NULL, 1, 1, &p->percentProcessorTime);
// rrddim_hide(p->st2, "idle");
//
// if(!is_total)
// rrdlabels_add(p->st->rrdlabels, "cpu", buffer, RRDLABEL_SRC_AUTO);
// }
//
// perflib_rrddim_set_by_pointer(p->st2, p->rd2_busy, &p->percentProcessorTime);
// rrdset_done(p->st2);
}
if(cpus_var)
rrdvar_host_variable_set(localhost, cpus_var, cores_found);
return true;
}
int do_PerflibProcessor(int update_every, usec_t dt __maybe_unused) {
static bool initialized = false;
if(unlikely(!initialized)) {
initialize();
initialized = true;
}
DWORD id = RegistryFindIDByName("Processor");
if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
return -1;
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
if(!pDataBlock) return -1;
do_processors(pDataBlock, update_every);
return 0;
}

View file

@ -0,0 +1,411 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "perflib-rrd.h"
#define COLLECTED_NUMBER_PRECISION 10000
RRDDIM *perflib_rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divider, COUNTER_DATA *cd) {
RRD_ALGORITHM algorithm = RRD_ALGORITHM_ABSOLUTE;
switch (cd->current.CounterType) {
case PERF_COUNTER_COUNTER:
case PERF_SAMPLE_COUNTER:
case PERF_COUNTER_BULK_COUNT:
// (N1 - N0) / ((D1 - D0) / F)
// multiplier *= cd->current.Frequency / 10000000;
// tested, the frequency is not that useful for netdata
// we get right results without it.
algorithm = RRD_ALGORITHM_INCREMENTAL;
break;
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
case PERF_AVERAGE_BULK: // normally not displayed
// (N1 - N0) / (D1 - D0)
algorithm = RRD_ALGORITHM_INCREMENTAL;
break;
case PERF_OBJ_TIME_TIMER:
case PERF_COUNTER_TIMER:
case PERF_100NSEC_TIMER:
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
case PERF_SAMPLE_FRACTION:
// 100 * (N1 - N0) / (D1 - D0)
multiplier *= 100;
algorithm = RRD_ALGORITHM_INCREMENTAL;
break;
case PERF_COUNTER_TIMER_INV:
case PERF_100NSEC_TIMER_INV:
// 100 * (1 - ((N1 - N0) / (D1 - D0)))
divider *= COLLECTED_NUMBER_PRECISION;
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_MULTI_TIMER:
// 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
divider *= COLLECTED_NUMBER_PRECISION;
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_100NSEC_MULTI_TIMER:
// 100 * ((N1 - N0) / (D1 - D0)) / B1
divider *= COLLECTED_NUMBER_PRECISION;
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_MULTI_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER_INV:
// 100 * (B1 - ((N1 - N0) / (D1 - D0)))
divider *= COLLECTED_NUMBER_PRECISION;
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT:
// N as decimal
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
// N as hexadecimal
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_DELTA:
case PERF_COUNTER_LARGE_DELTA:
// N1 - N0
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_RAW_FRACTION:
case PERF_LARGE_RAW_FRACTION:
// 100 * N / B
algorithm = RRD_ALGORITHM_ABSOLUTE;
divider *= COLLECTED_NUMBER_PRECISION;
break;
case PERF_AVERAGE_TIMER:
// ((N1 - N0) / TB) / (B1 - B0)
// divider *= cd->current.Frequency / 10000000;
algorithm = RRD_ALGORITHM_INCREMENTAL;
break;
case PERF_ELAPSED_TIME:
// (D0 - N0) / F
algorithm = RRD_ALGORITHM_ABSOLUTE;
break;
case PERF_COUNTER_TEXT:
case PERF_SAMPLE_BASE:
case PERF_AVERAGE_BASE:
case PERF_COUNTER_MULTI_BASE:
case PERF_RAW_BASE:
case PERF_COUNTER_NODATA:
case PERF_PRECISION_TIMESTAMP:
default:
break;
}
return rrddim_add(st, id, name, multiplier, divider, algorithm);
}
#define VALID_DELTA(cd) \
((cd)->previous.Time > 0 && (cd)->current.Data >= (cd)->previous.Data && (cd)->current.Time > (cd)->previous.Time)
collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd) {
ULONGLONG numerator = 0;
LONGLONG denominator = 0;
double doubleValue = 0.0;
collected_number value;
switch(cd->current.CounterType) {
case PERF_COUNTER_COUNTER:
case PERF_SAMPLE_COUNTER:
case PERF_COUNTER_BULK_COUNT:
// (N1 - N0) / ((D1 - D0) / F)
value = (collected_number)cd->current.Data;
break;
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
case PERF_AVERAGE_BULK: // normally not displayed
// (N1 - N0) / (D1 - D0)
value = (collected_number)cd->current.Data;
break;
case PERF_OBJ_TIME_TIMER:
case PERF_COUNTER_TIMER:
case PERF_100NSEC_TIMER:
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
case PERF_SAMPLE_FRACTION:
// 100 * (N1 - N0) / (D1 - D0)
value = (collected_number)cd->current.Data;
break;
case PERF_COUNTER_TIMER_INV:
case PERF_100NSEC_TIMER_INV:
// 100 * (1 - ((N1 - N0) / (D1 - D0)))
if(!VALID_DELTA(cd)) return 0;
numerator = cd->current.Data - cd->previous.Data;
denominator = cd->current.Time - cd->previous.Time;
doubleValue = 100.0 * (1.0 - ((double)numerator / (double)denominator));
// printf("Display value is (timer-inv): %f%%\n", doubleValue);
value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
break;
case PERF_COUNTER_MULTI_TIMER:
// 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
if(!VALID_DELTA(cd)) return 0;
numerator = cd->current.Data - cd->previous.Data;
denominator = cd->current.Time - cd->previous.Time;
denominator /= cd->current.Frequency;
doubleValue = 100.0 * ((double)numerator / (double)denominator) / cd->current.MultiCounterData;
// printf("Display value is (multi-timer): %f%%\n", doubleValue);
value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
break;
case PERF_100NSEC_MULTI_TIMER:
// 100 * ((N1 - N0) / (D1 - D0)) / B1
if(!VALID_DELTA(cd)) return 0;
numerator = cd->current.Data - cd->previous.Data;
denominator = cd->current.Time - cd->previous.Time;
doubleValue = 100.0 * ((double)numerator / (double)denominator) / (double)cd->current.MultiCounterData;
// printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
break;
case PERF_COUNTER_MULTI_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER_INV:
// 100 * (B1 - ((N1 - N0) / (D1 - D0)))
if(!VALID_DELTA(cd)) return 0;
numerator = cd->current.Data - cd->previous.Data;
denominator = cd->current.Time - cd->previous.Time;
doubleValue = 100.0 * ((double)cd->current.MultiCounterData - ((double)numerator / (double)denominator));
// printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
break;
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT:
// N as decimal
value = (collected_number)cd->current.Data;
break;
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
// N as hexadecimal
value = (collected_number)cd->current.Data;
break;
case PERF_COUNTER_DELTA:
case PERF_COUNTER_LARGE_DELTA:
if(!VALID_DELTA(cd)) return 0;
value = (collected_number)(cd->current.Data - cd->previous.Data);
break;
case PERF_RAW_FRACTION:
case PERF_LARGE_RAW_FRACTION:
// 100 * N / B
if(!cd->current.Time) return 0;
doubleValue = 100.0 * (double)cd->current.Data / (double)cd->current.Time;
// printf("Display value is (fraction): %f%%\n", doubleValue);
value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
break;
default:
return 0;
}
return rrddim_set_by_pointer(st, rd, value);
}
/*
double perflibCalculateValue(RAW_DATA *current, RAW_DATA *previous) {
ULONGLONG numerator = 0;
LONGLONG denominator = 0;
double doubleValue = 0.0;
DWORD dwordValue = 0;
if (NULL == previous) {
// Return error if the counter type requires two samples to calculate the value.
switch (current->CounterType) {
default:
if (PERF_DELTA_COUNTER != (current->CounterType & PERF_DELTA_COUNTER))
break;
__fallthrough;
// fallthrough
case PERF_AVERAGE_TIMER: // Special case.
case PERF_AVERAGE_BULK: // Special case.
// printf(" > The counter type requires two samples but only one sample was provided.\n");
return NAN;
}
}
else {
if (current->CounterType != previous->CounterType) {
// printf(" > The samples have inconsistent counter types.\n");
return NAN;
}
// Check for integer overflow or bad data from provider (the data from
// sample 2 must be greater than the data from sample 1).
if (current->Data < previous->Data)
{
// Can happen for various reasons. Commonly occurs with the Process counterset when
// multiple processes have the same name and one of them starts or stops.
// Normally you'll just drop the older sample and continue.
// printf("> current (%llu) is smaller than previous (%llu).\n", current->Data, previous->Data);
return NAN;
}
}
switch (current->CounterType) {
case PERF_COUNTER_COUNTER:
case PERF_SAMPLE_COUNTER:
case PERF_COUNTER_BULK_COUNT:
// (N1 - N0) / ((D1 - D0) / F)
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
dwordValue = (DWORD)(numerator / ((double)denominator / current->Frequency));
//printf("Display value is (counter): %lu%s\n", (unsigned long)dwordValue,
// (previous->CounterType == PERF_SAMPLE_COUNTER) ? "" : "/sec");
return (double)dwordValue;
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
case PERF_AVERAGE_BULK: // normally not displayed
// (N1 - N0) / (D1 - D0)
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = (double)numerator / denominator;
if (previous->CounterType != PERF_AVERAGE_BULK) {
// printf("Display value is (queuelen): %f\n", doubleValue);
return doubleValue;
}
return NAN;
case PERF_OBJ_TIME_TIMER:
case PERF_COUNTER_TIMER:
case PERF_100NSEC_TIMER:
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
case PERF_SAMPLE_FRACTION:
// 100 * (N1 - N0) / (D1 - D0)
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = (double)(100 * numerator) / denominator;
// printf("Display value is (timer): %f%%\n", doubleValue);
return doubleValue;
case PERF_COUNTER_TIMER_INV:
// 100 * (1 - ((N1 - N0) / (D1 - D0)))
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = 100 * (1 - ((double)numerator / denominator));
// printf("Display value is (timer-inv): %f%%\n", doubleValue);
return doubleValue;
case PERF_100NSEC_TIMER_INV:
// 100 * (1- (N1 - N0) / (D1 - D0))
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = 100 * (1 - (double)numerator / denominator);
// printf("Display value is (100ns-timer-inv): %f%%\n", doubleValue);
return doubleValue;
case PERF_COUNTER_MULTI_TIMER:
// 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
denominator /= current->Frequency;
doubleValue = 100 * ((double)numerator / denominator) / current->MultiCounterData;
// printf("Display value is (multi-timer): %f%%\n", doubleValue);
return doubleValue;
case PERF_100NSEC_MULTI_TIMER:
// 100 * ((N1 - N0) / (D1 - D0)) / B1
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = 100 * ((double)numerator / (double)denominator) / (double)current->MultiCounterData;
// printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
return doubleValue;
case PERF_COUNTER_MULTI_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER_INV:
// 100 * (B1 - ((N1 - N0) / (D1 - D0)))
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = 100.0 * ((double)current->MultiCounterData - ((double)numerator / (double)denominator));
// printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
return doubleValue;
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT:
// N as decimal
// printf("Display value is (rawcount): %llu\n", current->Data);
return (double)current->Data;
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
// N as hexadecimal
// printf("Display value is (hex): 0x%llx\n", current->Data);
return (double)current->Data;
case PERF_COUNTER_DELTA:
case PERF_COUNTER_LARGE_DELTA:
// N1 - N0
// printf("Display value is (delta): %llu\n", current->Data - previous->Data);
return (double)(current->Data - previous->Data);
case PERF_RAW_FRACTION:
case PERF_LARGE_RAW_FRACTION:
// 100 * N / B
doubleValue = 100.0 * (double)current->Data / (double)current->Time;
// printf("Display value is (fraction): %f%%\n", doubleValue);
return doubleValue;
case PERF_AVERAGE_TIMER:
// ((N1 - N0) / TB) / (B1 - B0)
numerator = current->Data - previous->Data;
denominator = current->Time - previous->Time;
doubleValue = (double)numerator / (double)current->Frequency / (double)denominator;
// printf("Display value is (average timer): %f seconds\n", doubleValue);
return doubleValue;
case PERF_ELAPSED_TIME:
// (D0 - N0) / F
doubleValue = (double)(current->Time - current->Data) / (double)current->Frequency;
// printf("Display value is (elapsed time): %f seconds\n", doubleValue);
return doubleValue;
case PERF_COUNTER_TEXT:
case PERF_SAMPLE_BASE:
case PERF_AVERAGE_BASE:
case PERF_COUNTER_MULTI_BASE:
case PERF_RAW_BASE:
case PERF_COUNTER_NODATA:
case PERF_PRECISION_TIMESTAMP:
// printf(" > Non-printing counter type: 0x%08x\n", current->CounterType);
return NAN;
break;
default:
// printf(" > Unrecognized counter type: 0x%08x\n", current->CounterType);
return NAN;
break;
}
}
*/

View file

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_PERFLIB_RRD_H
#define NETDATA_PERFLIB_RRD_H
#include "perflib.h"
#include "database/rrd.h"
RRDDIM *perflib_rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divider, COUNTER_DATA *cd);
collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd);
#endif //NETDATA_PERFLIB_RRD_H

View file

@ -0,0 +1,317 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
#include "windows-internals.h"
#define _COMMON_PLUGIN_NAME PLUGIN_WINDOWS_NAME
#define _COMMON_PLUGIN_MODULE_NAME "PerflibStorage"
#include "../common-contexts/common-contexts.h"
struct logical_disk {
bool collected_metadata;
STRING *filesystem;
RRDSET *st_disk_space;
RRDDIM *rd_disk_space_used;
RRDDIM *rd_disk_space_free;
COUNTER_DATA percentDiskFree;
// COUNTER_DATA freeMegabytes;
};
struct physical_disk {
bool collected_metadata;
STRING *device;
STRING *mount_point;
ND_DISK_IO disk_io;
COUNTER_DATA diskReadBytesPerSec;
COUNTER_DATA diskWriteBytesPerSec;
COUNTER_DATA percentIdleTime;
COUNTER_DATA percentDiskTime;
COUNTER_DATA percentDiskReadTime;
COUNTER_DATA percentDiskWriteTime;
COUNTER_DATA currentDiskQueueLength;
COUNTER_DATA averageDiskQueueLength;
COUNTER_DATA averageDiskReadQueueLength;
COUNTER_DATA averageDiskWriteQueueLength;
COUNTER_DATA averageDiskSecondsPerTransfer;
COUNTER_DATA averageDiskSecondsPerRead;
COUNTER_DATA averageDiskSecondsPerWrite;
COUNTER_DATA diskTransfersPerSec;
COUNTER_DATA diskReadsPerSec;
COUNTER_DATA diskWritesPerSec;
COUNTER_DATA diskBytesPerSec;
COUNTER_DATA averageDiskBytesPerTransfer;
COUNTER_DATA averageDiskBytesPerRead;
COUNTER_DATA averageDiskBytesPerWrite;
COUNTER_DATA splitIoPerSec;
};
struct physical_disk system_physical_total = {
.collected_metadata = true,
};
void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
struct logical_disk *ld = value;
ld->percentDiskFree.key = "% Free Space";
// ld->freeMegabytes.key = "Free Megabytes";
}
void initialize_physical_disk(struct physical_disk *pd) {
pd->percentIdleTime.key = "% Idle Time";
pd->percentDiskTime.key = "% Disk Time";
pd->percentDiskReadTime.key = "% Disk Read Time";
pd->percentDiskWriteTime.key = "% Disk Write Time";
pd->currentDiskQueueLength.key = "Current Disk Queue Length";
pd->averageDiskQueueLength.key = "Avg. Disk Queue Length";
pd->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
pd->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
pd->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
pd->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
pd->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
pd->diskTransfersPerSec.key = "Disk Transfers/sec";
pd->diskReadsPerSec.key = "Disk Reads/sec";
pd->diskWritesPerSec.key = "Disk Writes/sec";
pd->diskBytesPerSec.key = "Disk Bytes/sec";
pd->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
pd->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
pd->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
pd->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
pd->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
pd->splitIoPerSec.key = "Split IO/Sec";
}
void dict_physical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
struct physical_disk *pd = value;
initialize_physical_disk(pd);
}
static DICTIONARY *logicalDisks = NULL, *physicalDisks = NULL;
static void initialize(void) {
initialize_physical_disk(&system_physical_total);
logicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct logical_disk));
dictionary_register_insert_callback(logicalDisks, dict_logical_disk_insert_cb, NULL);
physicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct physical_disk));
dictionary_register_insert_callback(physicalDisks, dict_physical_disk_insert_cb, NULL);
}
static STRING *getFileSystemType(const char* diskName) {
if (!diskName || !*diskName) return NULL;
char fileSystemNameBuffer[128] = {0}; // Buffer for file system name
char pathBuffer[256] = {0}; // Path buffer to accommodate different formats
DWORD serialNumber = 0;
DWORD maxComponentLength = 0;
DWORD fileSystemFlags = 0;
BOOL success;
// Check if the input is likely a drive letter (e.g., "C:")
if (isalpha((uint8_t)diskName[0]) && diskName[1] == ':' && diskName[2] == '\0')
snprintf(pathBuffer, sizeof(pathBuffer), "%s\\", diskName); // Format as "C:\\"
else
// Assume it's a Volume GUID path or a device path
snprintf(pathBuffer, sizeof(pathBuffer), "\\\\.\\%s", diskName); // Format as "\\.\HarddiskVolume1"
// Attempt to get the volume information
success = GetVolumeInformation(
pathBuffer, // Path to the disk
NULL, // We don't need the volume name
0, // Size of volume name buffer is 0
&serialNumber, // Volume serial number
&maxComponentLength, // Maximum component length
&fileSystemFlags, // File system flags
fileSystemNameBuffer, // File system name buffer
sizeof(fileSystemNameBuffer) // Size of file system name buffer
);
if (success && fileSystemNameBuffer[0]) {
char *s = fileSystemNameBuffer;
while(*s) { *s = tolower((uint8_t)*s); s++; }
return string_strdupz(fileSystemNameBuffer); // Duplicate the file system name
}
else
return NULL;
}
static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
DICTIONARY *dict = logicalDisks;
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "LogicalDisk");
if(!pObjectType) return false;
PERF_INSTANCE_DEFINITION *pi = NULL;
for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
if(!pi) break;
if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
if(strcasecmp(windows_shared_buffer, "_Total") == 0)
continue;
struct logical_disk *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
if(!d->collected_metadata) {
d->filesystem = getFileSystemType(windows_shared_buffer);
d->collected_metadata = true;
}
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskFree);
// perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->freeMegabytes);
if(!d->st_disk_space) {
d->st_disk_space = rrdset_create_localhost(
"disk_space"
, windows_shared_buffer, NULL
, windows_shared_buffer, "disk.space"
, "Disk Space Usage"
, "GiB"
, PLUGIN_WINDOWS_NAME
, "PerflibStorage"
, NETDATA_CHART_PRIO_DISKSPACE_SPACE
, update_every
, RRDSET_TYPE_STACKED
);
rrdlabels_add(d->st_disk_space->rrdlabels, "mount_point", windows_shared_buffer, RRDLABEL_SRC_AUTO);
// rrdlabels_add(d->st->rrdlabels, "mount_root", name, RRDLABEL_SRC_AUTO);
if(d->filesystem)
rrdlabels_add(d->st_disk_space->rrdlabels, "filesystem", string2str(d->filesystem), RRDLABEL_SRC_AUTO);
d->rd_disk_space_free = rrddim_add(d->st_disk_space, "avail", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
d->rd_disk_space_used = rrddim_add(d->st_disk_space, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
}
// percentDiskFree has the free space in Data and the size of the disk in Time, in MiB.
rrddim_set_by_pointer(d->st_disk_space, d->rd_disk_space_free, (collected_number)d->percentDiskFree.current.Data);
rrddim_set_by_pointer(d->st_disk_space, d->rd_disk_space_used, (collected_number)(d->percentDiskFree.current.Time - d->percentDiskFree.current.Data));
rrdset_done(d->st_disk_space);
}
return true;
}
static void physical_disk_labels(RRDSET *st, void *data) {
struct physical_disk *d = data;
if(d->device)
rrdlabels_add(st->rrdlabels, "device", string2str(d->device), RRDLABEL_SRC_AUTO);
if (d->mount_point)
rrdlabels_add(st->rrdlabels, "mount_point", string2str(d->mount_point), RRDLABEL_SRC_AUTO);
}
static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
DICTIONARY *dict = physicalDisks;
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "PhysicalDisk");
if(!pObjectType) return false;
PERF_INSTANCE_DEFINITION *pi = NULL;
for (LONG i = 0; i < pObjectType->NumInstances; i++) {
pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
if (!pi)
break;
if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
char *device = windows_shared_buffer;
char *mount_point = NULL;
if((mount_point = strchr(device, ' '))) {
*mount_point = '\0';
mount_point++;
}
struct physical_disk *d;
bool is_system;
if (strcasecmp(windows_shared_buffer, "_Total") == 0) {
d = &system_physical_total;
is_system = true;
}
else {
d = dictionary_set(dict, device, NULL, sizeof(*d));
is_system = false;
}
if (!d->collected_metadata) {
// TODO collect metadata - device_type, serial, id
d->device = string_strdupz(device);
d->mount_point = string_strdupz(mount_point);
d->collected_metadata = true;
}
if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadBytesPerSec) &&
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWriteBytesPerSec)) {
if(is_system)
common_system_io(d->diskReadBytesPerSec.current.Data, d->diskWriteBytesPerSec.current.Data, update_every);
else
common_disk_io(
&d->disk_io,
device,
NULL,
d->diskReadBytesPerSec.current.Data,
d->diskWriteBytesPerSec.current.Data,
update_every,
physical_disk_labels,
d);
}
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskQueueLength);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskReadQueueLength);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskWriteQueueLength);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerTransfer);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskTransfersPerSec);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskBytesPerSec);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerTransfer);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerWrite);
perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec);
}
return true;
}
int do_PerflibStorage(int update_every, usec_t dt __maybe_unused) {
static bool initialized = false;
if(unlikely(!initialized)) {
initialize();
initialized = true;
}
DWORD id = RegistryFindIDByName("LogicalDisk");
if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
return -1;
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
if(!pDataBlock) return -1;
do_logical_disk(pDataBlock, update_every);
do_physical_disk(pDataBlock, update_every);
return 0;
}

View file

@ -0,0 +1,671 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "perflib.h"
// --------------------------------------------------------------------------------
// Retrieve a buffer that contains the specified performance data.
// The pwszSource parameter determines the data that GetRegistryBuffer returns.
//
// Typically, when calling RegQueryValueEx, you can specify zero for the size of the buffer
// and the RegQueryValueEx will set your size variable to the required buffer size. However,
// if the source is "Global" or one or more object index values, you will need to increment
// the buffer size in a loop until RegQueryValueEx does not return ERROR_MORE_DATA.
static LPBYTE getPerformanceData(const char *pwszSource) {
static __thread DWORD size = 0;
static __thread LPBYTE buffer = NULL;
if(pwszSource == (const char *)0x01) {
freez(buffer);
buffer = NULL;
size = 0;
return NULL;
}
if(!size) {
size = 32 * 1024;
buffer = mallocz(size);
}
LONG status = ERROR_SUCCESS;
while ((status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, pwszSource,
NULL, NULL, buffer, &size)) == ERROR_MORE_DATA) {
size *= 2;
buffer = reallocz(buffer, size);
}
if (status != ERROR_SUCCESS) {
nd_log(NDLS_COLLECTORS, NDLP_ERR, "RegQueryValueEx failed with 0x%x.\n", status);
return NULL;
}
return buffer;
}
void perflibFreePerformanceData(void) {
getPerformanceData((const char *)0x01);
}
// --------------------------------------------------------------------------------------------------------------------
// Retrieve the raw counter value and any supporting data needed to calculate
// a displayable counter value. Use the counter type to determine the information
// needed to calculate the value.
static BOOL getCounterData(
PERF_DATA_BLOCK *pDataBlock,
PERF_OBJECT_TYPE* pObject,
PERF_COUNTER_DEFINITION* pCounter,
PERF_COUNTER_BLOCK* pCounterDataBlock,
PRAW_DATA pRawData)
{
PVOID pData = NULL;
UNALIGNED ULONGLONG* pullData = NULL;
PERF_COUNTER_DEFINITION* pBaseCounter = NULL;
BOOL fSuccess = TRUE;
//Point to the raw counter data.
pData = (PVOID)((LPBYTE)pCounterDataBlock + pCounter->CounterOffset);
//Now use the PERF_COUNTER_DEFINITION.CounterType value to figure out what
//other information you need to calculate a displayable value.
switch (pCounter->CounterType) {
case PERF_COUNTER_COUNTER:
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_SAMPLE_COUNTER:
pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
pRawData->Time = pDataBlock->PerfTime.QuadPart;
if (PERF_COUNTER_COUNTER == pCounter->CounterType || PERF_SAMPLE_COUNTER == pCounter->CounterType)
pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
break;
case PERF_OBJ_TIME_TIMER:
pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
pRawData->Time = pObject->PerfTime.QuadPart;
break;
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
pRawData->Data = *(UNALIGNED ULONGLONG *)pData;
pRawData->Time = pDataBlock->PerfTime100nSec.QuadPart;
break;
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
pRawData->Data = *(UNALIGNED ULONGLONG *)pData;
pRawData->Time = pObject->PerfTime.QuadPart;
break;
case PERF_COUNTER_TIMER:
case PERF_COUNTER_TIMER_INV:
case PERF_COUNTER_BULK_COUNT:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
pullData = (UNALIGNED ULONGLONG *)pData;
pRawData->Data = *pullData;
pRawData->Time = pDataBlock->PerfTime.QuadPart;
if (pCounter->CounterType == PERF_COUNTER_BULK_COUNT)
pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
break;
case PERF_COUNTER_MULTI_TIMER:
case PERF_COUNTER_MULTI_TIMER_INV:
pullData = (UNALIGNED ULONGLONG *)pData;
pRawData->Data = *pullData;
pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
pRawData->Time = pDataBlock->PerfTime.QuadPart;
//These counter types have a second counter value that is adjacent to
//this counter value in the counter data block. The value is needed for
//the calculation.
if ((pCounter->CounterType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
++pullData;
pRawData->MultiCounterData = *(DWORD*)pullData;
}
break;
//These counters do not use any time reference.
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_RAWCOUNT_HEX:
case PERF_COUNTER_DELTA:
// some counters in these categories, have CounterSize = sizeof(ULONGLONG)
// but the official documentation always uses them as sizeof(DWORD)
pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
pRawData->Time = 0;
break;
case PERF_COUNTER_LARGE_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
case PERF_COUNTER_LARGE_DELTA:
pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
pRawData->Time = 0;
break;
//These counters use the 100ns time base in their calculation.
case PERF_100NSEC_TIMER:
case PERF_100NSEC_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER:
case PERF_100NSEC_MULTI_TIMER_INV:
pullData = (UNALIGNED ULONGLONG*)pData;
pRawData->Data = *pullData;
pRawData->Time = pDataBlock->PerfTime100nSec.QuadPart;
//These counter types have a second counter value that is adjacent to
//this counter value in the counter data block. The value is needed for
//the calculation.
if ((pCounter->CounterType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
++pullData;
pRawData->MultiCounterData = *(DWORD*)pullData;
}
break;
//These counters use two data points, this value and one from this counter's
//base counter. The base counter should be the next counter in the object's
//list of counters.
case PERF_SAMPLE_FRACTION:
case PERF_RAW_FRACTION:
pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
pBaseCounter = pCounter + 1; //Get base counter
if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
pRawData->Time = (LONGLONG)(*(DWORD*)pData);
}
else
fSuccess = FALSE;
break;
case PERF_LARGE_RAW_FRACTION:
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
pBaseCounter = pCounter + 1;
if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
pRawData->Time = *(LONGLONG*)pData;
}
else
fSuccess = FALSE;
break;
case PERF_AVERAGE_TIMER:
case PERF_AVERAGE_BULK:
pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
pBaseCounter = pCounter+1;
if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
pRawData->Time = *(DWORD*)pData;
}
else
fSuccess = FALSE;
if (pCounter->CounterType == PERF_AVERAGE_TIMER)
pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
break;
//These are base counters and are used in calculations for other counters.
//This case should never be entered.
case PERF_SAMPLE_BASE:
case PERF_AVERAGE_BASE:
case PERF_COUNTER_MULTI_BASE:
case PERF_RAW_BASE:
case PERF_LARGE_RAW_BASE:
pRawData->Data = 0;
pRawData->Time = 0;
fSuccess = FALSE;
break;
case PERF_ELAPSED_TIME:
pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
pRawData->Time = pObject->PerfTime.QuadPart;
pRawData->Frequency = pObject->PerfFreq.QuadPart;
break;
//These counters are currently not supported.
case PERF_COUNTER_TEXT:
case PERF_COUNTER_NODATA:
case PERF_COUNTER_HISTOGRAM_TYPE:
default: // unknown counter types
pRawData->Data = 0;
pRawData->Time = 0;
fSuccess = FALSE;
break;
}
return fSuccess;
}
// --------------------------------------------------------------------------------------------------------------------
static inline BOOL isValidPointer(PERF_DATA_BLOCK *pDataBlock __maybe_unused, void *ptr __maybe_unused) {
#ifdef NETDATA_INTERNAL_CHECKS
return (PBYTE)ptr >= (PBYTE)pDataBlock + pDataBlock->TotalByteLength ? FALSE : TRUE;
#else
return TRUE;
#endif
}
static inline BOOL isValidStructure(PERF_DATA_BLOCK *pDataBlock __maybe_unused, void *ptr __maybe_unused, size_t length __maybe_unused) {
#ifdef NETDATA_INTERNAL_CHECKS
return (PBYTE)ptr + length > (PBYTE)pDataBlock + pDataBlock->TotalByteLength ? FALSE : TRUE;
#else
return TRUE;
#endif
}
static inline PERF_DATA_BLOCK *getDataBlock(BYTE *pBuffer) {
PERF_DATA_BLOCK *pDataBlock = (PERF_DATA_BLOCK *)pBuffer;
static WCHAR signature[] = { 'P', 'E', 'R', 'F' };
if(memcmp(pDataBlock->Signature, signature, sizeof(signature)) != 0) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid data block signature.");
return NULL;
}
if(!isValidPointer(pDataBlock, (PBYTE)pDataBlock + pDataBlock->SystemNameOffset) ||
!isValidStructure(pDataBlock, (PBYTE)pDataBlock + pDataBlock->SystemNameOffset, pDataBlock->SystemNameLength)) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid system name array.");
return NULL;
}
return pDataBlock;
}
static inline PERF_OBJECT_TYPE *getObjectType(PERF_DATA_BLOCK* pDataBlock, PERF_OBJECT_TYPE *lastObjectType) {
PERF_OBJECT_TYPE* pObjectType = NULL;
if(!lastObjectType)
pObjectType = (PERF_OBJECT_TYPE *)((PBYTE)pDataBlock + pDataBlock->HeaderLength);
else if (lastObjectType->TotalByteLength != 0)
pObjectType = (PERF_OBJECT_TYPE *)((PBYTE)lastObjectType + lastObjectType->TotalByteLength);
if(pObjectType && (!isValidPointer(pDataBlock, pObjectType) || !isValidStructure(pDataBlock, pObjectType, pObjectType->TotalByteLength))) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid ObjectType!");
pObjectType = NULL;
}
return pObjectType;
}
inline PERF_OBJECT_TYPE *getObjectTypeByIndex(PERF_DATA_BLOCK *pDataBlock, DWORD ObjectNameTitleIndex) {
PERF_OBJECT_TYPE *po = NULL;
for(DWORD o = 0; o < pDataBlock->NumObjectTypes ; o++) {
po = getObjectType(pDataBlock, po);
if(po->ObjectNameTitleIndex == ObjectNameTitleIndex)
return po;
}
return NULL;
}
static inline PERF_INSTANCE_DEFINITION *getInstance(
PERF_DATA_BLOCK *pDataBlock,
PERF_OBJECT_TYPE *pObjectType,
PERF_COUNTER_BLOCK *lastCounterBlock
) {
PERF_INSTANCE_DEFINITION *pInstance;
if(!lastCounterBlock)
pInstance = (PERF_INSTANCE_DEFINITION *)((PBYTE)pObjectType + pObjectType->DefinitionLength);
else
pInstance = (PERF_INSTANCE_DEFINITION *)((PBYTE)lastCounterBlock + lastCounterBlock->ByteLength);
if(pInstance && (!isValidPointer(pDataBlock, pInstance) || !isValidStructure(pDataBlock, pInstance, pInstance->ByteLength))) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid Instance Definition!");
pInstance = NULL;
}
return pInstance;
}
static inline PERF_COUNTER_BLOCK *getObjectTypeCounterBlock(
PERF_DATA_BLOCK *pDataBlock,
PERF_OBJECT_TYPE *pObjectType
) {
PERF_COUNTER_BLOCK *pCounterBlock = (PERF_COUNTER_BLOCK *)((PBYTE)pObjectType + pObjectType->DefinitionLength);
if(pCounterBlock && (!isValidPointer(pDataBlock, pCounterBlock) || !isValidStructure(pDataBlock, pCounterBlock, pCounterBlock->ByteLength))) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid ObjectType CounterBlock!");
pCounterBlock = NULL;
}
return pCounterBlock;
}
static inline PERF_COUNTER_BLOCK *getInstanceCounterBlock(
PERF_DATA_BLOCK *pDataBlock,
PERF_OBJECT_TYPE *pObjectType,
PERF_INSTANCE_DEFINITION *pInstance
) {
(void)pObjectType;
PERF_COUNTER_BLOCK *pCounterBlock = (PERF_COUNTER_BLOCK *)((PBYTE)pInstance + pInstance->ByteLength);
if(pCounterBlock && (!isValidPointer(pDataBlock, pCounterBlock) || !isValidStructure(pDataBlock, pCounterBlock, pCounterBlock->ByteLength))) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid Instance CounterBlock!");
pCounterBlock = NULL;
}
return pCounterBlock;
}
inline PERF_INSTANCE_DEFINITION *getInstanceByPosition(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, DWORD instancePosition) {
PERF_INSTANCE_DEFINITION *pi = NULL;
PERF_COUNTER_BLOCK *pc = NULL;
for(DWORD i = 0; i <= instancePosition ;i++) {
pi = getInstance(pDataBlock, pObjectType, pc);
pc = getInstanceCounterBlock(pDataBlock, pObjectType, pi);
}
return pi;
}
static inline PERF_COUNTER_DEFINITION *getCounterDefinition(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *lastCounterDefinition) {
PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
if(!lastCounterDefinition)
pCounterDefinition = (PERF_COUNTER_DEFINITION *)((PBYTE)pObjectType + pObjectType->HeaderLength);
else
pCounterDefinition = (PERF_COUNTER_DEFINITION *)((PBYTE)lastCounterDefinition + lastCounterDefinition->ByteLength);
if(pCounterDefinition && (!isValidPointer(pDataBlock, pCounterDefinition) || !isValidStructure(pDataBlock, pCounterDefinition, pCounterDefinition->ByteLength))) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Invalid Counter Definition!");
pCounterDefinition = NULL;
}
return pCounterDefinition;
}
// --------------------------------------------------------------------------------------------------------------------
static inline BOOL getEncodedStringToUTF8(char *dst, size_t dst_len, DWORD CodePage, char *start, DWORD length) {
WCHAR *tempBuffer; // Temporary buffer for Unicode data
DWORD charsCopied = 0;
BOOL free_tempBuffer;
if (CodePage == 0) {
// Input is already Unicode (UTF-16)
tempBuffer = (WCHAR *)start;
charsCopied = length / sizeof(WCHAR); // Convert byte length to number of WCHARs
free_tempBuffer = FALSE;
}
else {
// Convert the multi-byte instance name to Unicode (UTF-16)
// Calculate maximum possible characters in UTF-16
int charCount = MultiByteToWideChar(CodePage, 0, start, (int)length, NULL, 0);
tempBuffer = (WCHAR *)malloc(charCount * sizeof(WCHAR));
if (!tempBuffer) return FALSE;
charsCopied = MultiByteToWideChar(CodePage, 0, start, (int)length, tempBuffer, charCount);
if (charsCopied == 0) {
free(tempBuffer);
dst[0] = '\0';
return FALSE;
}
free_tempBuffer = TRUE;
}
// Now convert from Unicode (UTF-16) to UTF-8
int bytesCopied = WideCharToMultiByte(CP_UTF8, 0, tempBuffer, (int)charsCopied, dst, (int)dst_len, NULL, NULL);
if (bytesCopied == 0) {
if (free_tempBuffer) free(tempBuffer);
dst[0] = '\0'; // Ensure the buffer is null-terminated even on failure
return FALSE;
}
dst[bytesCopied] = '\0'; // Ensure buffer is null-terminated
if (free_tempBuffer) free(tempBuffer); // Free temporary buffer if used
return TRUE;
}
inline BOOL getInstanceName(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance,
char *buffer, size_t bufferLen) {
(void)pDataBlock;
if (!pInstance || !buffer || !bufferLen) return FALSE;
return getEncodedStringToUTF8(buffer, bufferLen, pObjectType->CodePage,
((char *)pInstance + pInstance->NameOffset), pInstance->NameLength);
}
inline BOOL getSystemName(PERF_DATA_BLOCK *pDataBlock, char *buffer, size_t bufferLen) {
return getEncodedStringToUTF8(buffer, bufferLen, 0,
((char *)pDataBlock + pDataBlock->SystemNameOffset), pDataBlock->SystemNameLength);
}
inline bool ObjectTypeHasInstances(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType) {
(void)pDataBlock;
return pObjectType->NumInstances != PERF_NO_INSTANCES && pObjectType->NumInstances > 0;
}
PERF_OBJECT_TYPE *perflibFindObjectTypeByName(PERF_DATA_BLOCK *pDataBlock, const char *name) {
PERF_OBJECT_TYPE* pObjectType = NULL;
for(DWORD o = 0; o < pDataBlock->NumObjectTypes; o++) {
pObjectType = getObjectType(pDataBlock, pObjectType);
if(strcmp(name, RegistryFindNameByID(pObjectType->ObjectNameTitleIndex)) == 0)
return pObjectType;
}
return NULL;
}
PERF_INSTANCE_DEFINITION *perflibForEachInstance(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *lastInstance) {
if(!ObjectTypeHasInstances(pDataBlock, pObjectType))
return NULL;
return getInstance(pDataBlock, pObjectType,
lastInstance ?
getInstanceCounterBlock(pDataBlock, pObjectType, lastInstance) :
NULL );
}
bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd) {
PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
if(!pCounterDefinition) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
c, pObjectType->NumCounters);
break;
}
if(cd->id) {
if(cd->id != pCounterDefinition->CounterNameTitleIndex)
continue;
}
else {
if(strcmp(RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex), cd->key) != 0)
continue;
cd->id = pCounterDefinition->CounterNameTitleIndex;
}
cd->current.CounterType = cd->OverwriteCounterType ? cd->OverwriteCounterType : pCounterDefinition->CounterType;
PERF_COUNTER_BLOCK *pCounterBlock = getInstanceCounterBlock(pDataBlock, pObjectType, pInstance);
cd->previous = cd->current;
cd->updated = getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current);
return cd->updated;
}
cd->previous = cd->current;
cd->current = RAW_DATA_EMPTY;
cd->updated = false;
return false;
}
bool perflibGetObjectCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, COUNTER_DATA *cd) {
PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
if(!pCounterDefinition) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
c, pObjectType->NumCounters);
break;
}
if(cd->id) {
if(cd->id != pCounterDefinition->CounterNameTitleIndex)
continue;
}
else {
if(strcmp(RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex), cd->key) != 0)
continue;
cd->id = pCounterDefinition->CounterNameTitleIndex;
}
cd->current.CounterType = cd->OverwriteCounterType ? cd->OverwriteCounterType : pCounterDefinition->CounterType;
PERF_COUNTER_BLOCK *pCounterBlock = getObjectTypeCounterBlock(pDataBlock, pObjectType);
cd->previous = cd->current;
cd->updated = getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current);
return cd->updated;
}
cd->previous = cd->current;
cd->current = RAW_DATA_EMPTY;
cd->updated = false;
return false;
}
PERF_DATA_BLOCK *perflibGetPerformanceData(DWORD id) {
char source[24];
snprintfz(source, sizeof(source), "%u", id);
LPBYTE pData = (LPBYTE)getPerformanceData((id > 0) ? source : NULL);
if (!pData) return NULL;
PERF_DATA_BLOCK *pDataBlock = getDataBlock(pData);
if(!pDataBlock) return NULL;
return pDataBlock;
}
int perflibQueryAndTraverse(DWORD id,
perflib_data_cb dataCb,
perflib_object_cb objectCb,
perflib_instance_cb instanceCb,
perflib_instance_counter_cb instanceCounterCb,
perflib_counter_cb counterCb,
void *data) {
int counters = -1;
PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
if(!pDataBlock) goto cleanup;
bool do_data = true;
if(dataCb)
do_data = dataCb(pDataBlock, data);
PERF_OBJECT_TYPE* pObjectType = NULL;
for(DWORD o = 0; do_data && o < pDataBlock->NumObjectTypes; o++) {
pObjectType = getObjectType(pDataBlock, pObjectType);
if(!pObjectType) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read object type No %d (out of %d)",
o, pDataBlock->NumObjectTypes);
break;
}
bool do_object = true;
if(objectCb)
do_object = objectCb(pDataBlock, pObjectType, data);
if(!do_object)
continue;
if(ObjectTypeHasInstances(pDataBlock, pObjectType)) {
PERF_INSTANCE_DEFINITION *pInstance = NULL;
PERF_COUNTER_BLOCK *pCounterBlock = NULL;
for(LONG i = 0; i < pObjectType->NumInstances ;i++) {
pInstance = getInstance(pDataBlock, pObjectType, pCounterBlock);
if(!pInstance) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read Instance No %d (out of %d)",
i, pObjectType->NumInstances);
break;
}
pCounterBlock = getInstanceCounterBlock(pDataBlock, pObjectType, pInstance);
if(!pCounterBlock) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read CounterBlock of instance No %d (out of %d)",
i, pObjectType->NumInstances);
break;
}
bool do_instance = true;
if(instanceCb)
do_instance = instanceCb(pDataBlock, pObjectType, pInstance, data);
if(!do_instance)
continue;
PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
if(!pCounterDefinition) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
c, pObjectType->NumCounters);
break;
}
RAW_DATA sample = {
.CounterType = pCounterDefinition->CounterType,
};
if(getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &sample)) {
// DisplayCalculatedValue(&sample, &sample);
if(instanceCounterCb) {
instanceCounterCb(pDataBlock, pObjectType, pInstance, pCounterDefinition, &sample, data);
counters++;
}
}
}
if(instanceCb)
instanceCb(pDataBlock, pObjectType, NULL, data);
}
}
else {
PERF_COUNTER_BLOCK *pCounterBlock = getObjectTypeCounterBlock(pDataBlock, pObjectType);
PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
if(!pCounterDefinition) {
nd_log(NDLS_COLLECTORS, NDLP_ERR,
"WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
c, pObjectType->NumCounters);
break;
}
RAW_DATA sample = {
.CounterType = pCounterDefinition->CounterType,
};
if(getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &sample)) {
// DisplayCalculatedValue(&sample, &sample);
if(counterCb) {
counterCb(pDataBlock, pObjectType, pCounterDefinition, &sample, data);
counters++;
}
}
}
}
if(objectCb)
objectCb(pDataBlock, NULL, data);
}
cleanup:
return counters;
}

View file

@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_PERFLIB_H
#define NETDATA_PERFLIB_H
#include "libnetdata/libnetdata.h"
#include <windows.h>
const char *RegistryFindNameByID(DWORD id);
const char *RegistryFindHelpByID(DWORD id);
DWORD RegistryFindIDByName(const char *name);
#define PERFLIB_REGISTRY_NAME_NOT_FOUND (DWORD)-1
PERF_DATA_BLOCK *perflibGetPerformanceData(DWORD id);
void perflibFreePerformanceData(void);
PERF_OBJECT_TYPE *perflibFindObjectTypeByName(PERF_DATA_BLOCK *pDataBlock, const char *name);
PERF_INSTANCE_DEFINITION *perflibForEachInstance(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *lastInstance);
typedef struct _rawdata {
DWORD CounterType;
DWORD MultiCounterData; // Second raw counter value for multi-valued counters
ULONGLONG Data; // Raw counter data
LONGLONG Time; // Is a time value or a base value
LONGLONG Frequency;
} RAW_DATA, *PRAW_DATA;
typedef struct _counterdata {
DWORD id;
bool updated;
const char *key;
DWORD OverwriteCounterType; // if set, the counter type will be overwritten once read
RAW_DATA current;
RAW_DATA previous;
} COUNTER_DATA;
#define RAW_DATA_EMPTY (RAW_DATA){ 0 }
bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd);
bool perflibGetObjectCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, COUNTER_DATA *cd);
typedef bool (*perflib_data_cb)(PERF_DATA_BLOCK *pDataBlock, void *data);
typedef bool (*perflib_object_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, void *data);
typedef bool (*perflib_instance_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, void *data);
typedef bool (*perflib_instance_counter_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data);
typedef bool (*perflib_counter_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data);
int perflibQueryAndTraverse(DWORD id,
perflib_data_cb dataCb,
perflib_object_cb objectCb,
perflib_instance_cb instanceCb,
perflib_instance_counter_cb instanceCounterCb,
perflib_counter_cb counterCb,
void *data);
bool ObjectTypeHasInstances(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType);
BOOL getInstanceName(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance,
char *buffer, size_t bufferLen);
BOOL getSystemName(PERF_DATA_BLOCK *pDataBlock, char *buffer, size_t bufferLen);
PERF_OBJECT_TYPE *getObjectTypeByIndex(PERF_DATA_BLOCK *pDataBlock, DWORD ObjectNameTitleIndex);
PERF_INSTANCE_DEFINITION *getInstanceByPosition(
PERF_DATA_BLOCK *pDataBlock,
PERF_OBJECT_TYPE *pObjectType,
DWORD instancePosition);
void PerflibNamesRegistryInitialize(void);
void PerflibNamesRegistryUpdate(void);
#endif //NETDATA_PERFLIB_H

View file

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_WINDOWS_INTERNALS_H
#define NETDATA_WINDOWS_INTERNALS_H
#include <windows.h>
static inline ULONGLONG FileTimeToULL(FILETIME ft) {
ULARGE_INTEGER ul;
ul.LowPart = ft.dwLowDateTime;
ul.HighPart = ft.dwHighDateTime;
return ul.QuadPart;
}
#include "perflib.h"
#include "perflib-rrd.h"
#endif //NETDATA_WINDOWS_INTERNALS_H

View file

@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "windows_plugin.h"
char windows_shared_buffer[8192];
static struct proc_module {
const char *name;
const char *dim;
int enabled;
int (*func)(int update_every, usec_t dt);
RRDDIM *rd;
} win_modules[] = {
// system metrics
{.name = "GetSystemUptime", .dim = "GetSystemUptime", .func = do_GetSystemUptime},
{.name = "GetSystemRAM", .dim = "GetSystemRAM", .func = do_GetSystemRAM},
// the same is provided by PerflibProcessor, with more detailed analysis
//{.name = "GetSystemCPU", .dim = "GetSystemCPU", .func = do_GetSystemCPU},
{.name = "PerflibProcessor", .dim = "PerflibProcessor", .func = do_PerflibProcessor},
{.name = "PerflibMemory", .dim = "PerflibMemory", .func = do_PerflibMemory},
{.name = "PerflibStorage", .dim = "PerflibStorage", .func = do_PerflibStorage},
{.name = "PerflibNetwork", .dim = "PerflibNetwork", .func = do_PerflibNetwork},
// the terminator of this array
{.name = NULL, .dim = NULL, .func = NULL}
};
#if WORKER_UTILIZATION_MAX_JOB_TYPES < 36
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 36
#endif
static void windows_main_cleanup(void *pptr) {
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
collector_info("cleaning up...");
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
worker_unregister();
}
static bool log_windows_module(BUFFER *wb, void *data) {
struct proc_module *pm = data;
buffer_sprintf(wb, PLUGIN_WINDOWS_NAME "[%s]", pm->name);
return true;
}
void *win_plugin_main(void *ptr) {
worker_register("WIN");
rrd_collector_started();
PerflibNamesRegistryInitialize();
CLEANUP_FUNCTION_REGISTER(windows_main_cleanup) cleanup_ptr = ptr;
// check the enabled status for each module
int i;
for(i = 0; win_modules[i].name; i++) {
struct proc_module *pm = &win_modules[i];
pm->enabled = config_get_boolean("plugin:windows", pm->name, CONFIG_BOOLEAN_YES);
pm->rd = NULL;
worker_register_job_name(i, win_modules[i].dim);
}
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
#define LGS_MODULE_ID 0
ND_LOG_STACK lgs[] = {
[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, PLUGIN_WINDOWS_NAME),
ND_LOG_FIELD_END(),
};
ND_LOG_STACK_PUSH(lgs);
while(service_running(SERVICE_COLLECTORS)) {
worker_is_idle();
usec_t hb_dt = heartbeat_next(&hb, step);
if(unlikely(!service_running(SERVICE_COLLECTORS)))
break;
PerflibNamesRegistryUpdate();
for(i = 0; win_modules[i].name; i++) {
if(unlikely(!service_running(SERVICE_COLLECTORS)))
break;
struct proc_module *pm = &win_modules[i];
if(unlikely(!pm->enabled))
continue;
worker_is_busy(i);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_windows_module, pm);
pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, PLUGIN_WINDOWS_NAME);
}
}
return NULL;
}

View file

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_WINDOWS_PLUGIN_H
#define NETDATA_WINDOWS_PLUGIN_H
#include "daemon/common.h"
#define PLUGIN_WINDOWS_NAME "windows.plugin"
void *win_plugin_main(void *ptr);
extern char windows_shared_buffer[8192];
int do_GetSystemUptime(int update_every, usec_t dt);
int do_GetSystemRAM(int update_every, usec_t dt);
int do_GetSystemCPU(int update_every, usec_t dt);
int do_PerflibStorage(int update_every, usec_t dt);
int do_PerflibNetwork(int update_every, usec_t dt);
int do_PerflibProcessor(int update_every, usec_t dt);
int do_PerflibMemory(int update_every, usec_t dt);
#include "perflib.h"
#endif //NETDATA_WINDOWS_PLUGIN_H

View file

@ -223,7 +223,7 @@ void analytics_mirrored_hosts(void)
count++;
}
rrd_unlock();
rrd_rdunlock();
snprintfz(b, sizeof(b) - 1, "%zu", count);
analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
@ -562,9 +562,11 @@ void analytics_gather_mutable_meta_data(void)
}
}
void analytics_main_cleanup(void *ptr)
void analytics_main_cleanup(void *pptr)
{
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
if(!static_thread) return;
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
netdata_log_debug(D_ANALYTICS, "Cleaning up...");
@ -581,7 +583,7 @@ void analytics_main_cleanup(void *ptr)
*/
void *analytics_main(void *ptr)
{
netdata_thread_cleanup_push(analytics_main_cleanup, ptr);
CLEANUP_FUNCTION_REGISTER(analytics_main_cleanup) cleanup_ptr = ptr;
unsigned int sec = 0;
heartbeat_t hb;
heartbeat_init(&hb);
@ -626,7 +628,6 @@ void *analytics_main(void *ptr)
}
cleanup:
netdata_thread_cleanup_pop(1);
return NULL;
}
@ -777,7 +778,7 @@ void get_system_timezone(void)
*d = '\0';
while (*timezone) {
if (isalnum(*timezone) || *timezone == '_' || *timezone == '/')
if (isalnum((uint8_t)*timezone) || *timezone == '_' || *timezone == '/')
*d++ = *timezone++;
else
timezone++;
@ -816,11 +817,11 @@ void get_system_timezone(void)
} else {
sign[0] = zone[0] == '-' || zone[0] == '+' ? zone[0] : '0';
sign[1] = '\0';
hh[0] = isdigit(zone[1]) ? zone[1] : '0';
hh[1] = isdigit(zone[2]) ? zone[2] : '0';
hh[0] = isdigit((uint8_t)zone[1]) ? zone[1] : '0';
hh[1] = isdigit((uint8_t)zone[2]) ? zone[2] : '0';
hh[2] = '\0';
mm[0] = isdigit(zone[3]) ? zone[3] : '0';
mm[1] = isdigit(zone[4]) ? zone[4] : '0';
mm[0] = isdigit((uint8_t)zone[3]) ? zone[3] : '0';
mm[1] = isdigit((uint8_t)zone[4]) ? zone[4] : '0';
mm[2] = '\0';
netdata_configured_utc_offset = (str2i(hh) * 3600) + (str2i(mm) * 60);

View file

@ -1058,6 +1058,16 @@ __attribute__((constructor)) void initialize_build_info(void) {
build_info_set_value(BIB_FEATURE_BUILT_FOR, "MacOS");
build_info_set_status(BIB_PLUGIN_MACOS, true);
#endif
#ifdef COMPILED_FOR_WINDOWS
build_info_set_status(BIB_FEATURE_BUILT_FOR, true);
#if defined(__CYGWIN__) && defined(__MSYS__)
build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows (MSYS)");
#elif defined(__CYGWIN__)
build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows (CYGWIN)");
#else
build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows");
#endif
#endif
#ifdef ENABLE_ACLK
build_info_set_status(BIB_FEATURE_CLOUD, true);

Some files were not shown because too many files have changed in this diff Show more