mirror of
https://github.com/netdata/netdata.git
synced 2025-04-16 18:37:50 +00:00
Windows Support Phase 1 (#17497)
* 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:
parent
c401ef6ac4
commit
fe06e8495f
283 changed files with 7477 additions and 2852 deletions
CMakeLists.txt
packaging
cmake
utils
src
aclk
claim
collectors
all.h
apps.plugin
cgroups.plugin
common-contexts
diskspace.plugin
ebpf.plugin
ebpf.cebpf.hebpf_cachestat.cebpf_cgroup.cebpf_dcstat.cebpf_disk.cebpf_fd.cebpf_filesystem.cebpf_functions.cebpf_hardirq.cebpf_mdflush.cebpf_mount.cebpf_oomkill.cebpf_process.cebpf_shm.cebpf_socket.cebpf_softirq.cebpf_swap.cebpf_sync.cebpf_vfs.c
freebsd.plugin
freeipmi.plugin
idlejitter.plugin
log2journal
macos.plugin
network-viewer.plugin
perf.plugin
plugins.d
ndsudo.cplugins_d.cplugins_d.hpluginsd_functions.hpluginsd_internals.hpluginsd_parser.cpluginsd_parser.h
proc.plugin
plugin_proc.cplugin_proc.hproc_diskstats.cproc_loadavg.cproc_meminfo.cproc_net_dev.cproc_net_netstat.cproc_stat.cproc_vmstat.c
profile.plugin
statsd.plugin
systemd-journal.plugin
tc.plugin
timex.plugin
windows.plugin
daemon
152
CMakeLists.txt
152
CMakeLists.txt
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
19
packaging/utils/bash_execute.sh
Normal file
19
packaging/utils/bash_execute.sh
Normal 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[@]}"
|
17
packaging/utils/clion-msys-mingw64-environment.bat
Normal file
17
packaging/utils/clion-msys-mingw64-environment.bat
Normal 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
|
20
packaging/utils/clion-msys-msys-environment.bat
Normal file
20
packaging/utils/clion-msys-msys-environment.bat
Normal 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
|
71
packaging/utils/compile-on-windows.sh
Normal file
71
packaging/utils/compile-on-windows.sh
Normal 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"
|
34
packaging/utils/installer.nsi
Normal file
34
packaging/utils/installer.nsi
Normal 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
|
27
packaging/utils/package-windows.sh
Normal file
27
packaging/utils/package-windows.sh
Normal 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"
|
9
packaging/utils/protoc.bat
Normal file
9
packaging/utils/protoc.bat
Normal 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 %*
|
118
packaging/utils/windows-openssh-to-msys.bat
Normal file
118
packaging/utils/windows-openssh-to-msys.bat
Normal 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
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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] = "";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
28
src/collectors/common-contexts/common-contexts.h
Normal file
28
src/collectors/common-contexts/common-contexts.h
Normal 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
|
44
src/collectors/common-contexts/disk.io.h
Normal file
44
src/collectors/common-contexts/disk.io.h
Normal 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
|
35
src/collectors/common-contexts/mem.available.h
Normal file
35
src/collectors/common-contexts/mem.available.h
Normal 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
|
40
src/collectors/common-contexts/mem.pgfaults.h
Normal file
40
src/collectors/common-contexts/mem.pgfaults.h
Normal 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
|
35
src/collectors/common-contexts/mem.swap.h
Normal file
35
src/collectors/common-contexts/mem.swap.h
Normal 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);
|
||||
}
|
38
src/collectors/common-contexts/system.io.h
Normal file
38
src/collectors/common-contexts/system.io.h
Normal 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
|
68
src/collectors/common-contexts/system.ram.h
Normal file
68
src/collectors/common-contexts/system.ram.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "pluginsd_internals.h"
|
||||
|
||||
struct inflight_function {
|
||||
uuid_t transaction;
|
||||
nd_uuid_t transaction;
|
||||
|
||||
int code;
|
||||
int timeout_s;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
51
src/collectors/windows.plugin/GetSystemCPU.c
Normal file
51
src/collectors/windows.plugin/GetSystemCPU.c
Normal 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;
|
||||
}
|
34
src/collectors/windows.plugin/GetSystemRAM.c
Normal file
34
src/collectors/windows.plugin/GetSystemRAM.c
Normal 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;
|
||||
}
|
34
src/collectors/windows.plugin/GetSystemUptime.c
Normal file
34
src/collectors/windows.plugin/GetSystemUptime.c
Normal 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;
|
||||
}
|
529
src/collectors/windows.plugin/perflib-dump.c
Normal file
529
src/collectors/windows.plugin/perflib-dump.c
Normal 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;
|
||||
}
|
65
src/collectors/windows.plugin/perflib-memory.c
Normal file
65
src/collectors/windows.plugin/perflib-memory.c
Normal 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;
|
||||
}
|
242
src/collectors/windows.plugin/perflib-names.c
Normal file
242
src/collectors/windows.plugin/perflib-names.c
Normal 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);
|
||||
}
|
||||
}
|
453
src/collectors/windows.plugin/perflib-network.c
Normal file
453
src/collectors/windows.plugin/perflib-network.c
Normal 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;
|
||||
}
|
191
src/collectors/windows.plugin/perflib-processor.c
Normal file
191
src/collectors/windows.plugin/perflib-processor.c
Normal 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;
|
||||
}
|
411
src/collectors/windows.plugin/perflib-rrd.c
Normal file
411
src/collectors/windows.plugin/perflib-rrd.c
Normal 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;
|
||||
}
|
||||
}
|
||||
*/
|
12
src/collectors/windows.plugin/perflib-rrd.h
Normal file
12
src/collectors/windows.plugin/perflib-rrd.h
Normal 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
|
317
src/collectors/windows.plugin/perflib-storage.c
Normal file
317
src/collectors/windows.plugin/perflib-storage.c
Normal 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;
|
||||
}
|
671
src/collectors/windows.plugin/perflib.c
Normal file
671
src/collectors/windows.plugin/perflib.c
Normal 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;
|
||||
}
|
72
src/collectors/windows.plugin/perflib.h
Normal file
72
src/collectors/windows.plugin/perflib.h
Normal 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
|
18
src/collectors/windows.plugin/windows-internals.h
Normal file
18
src/collectors/windows.plugin/windows-internals.h
Normal 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
|
109
src/collectors/windows.plugin/windows_plugin.c
Normal file
109
src/collectors/windows.plugin/windows_plugin.c
Normal 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;
|
||||
}
|
24
src/collectors/windows.plugin/windows_plugin.h
Normal file
24
src/collectors/windows.plugin/windows_plugin.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue