feat add profiling
This commit is contained in:
114
3party/cppuprofile/lib/CMakeLists.txt
Normal file
114
3party/cppuprofile/lib/CMakeLists.txt
Normal file
@@ -0,0 +1,114 @@
|
||||
PROJECT(cppuprofile DESCRIPTION "CppProfiling library")
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
|
||||
|
||||
SET( CMAKE_USE_RELATIVE_PATHS ON)
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
ADD_DEFINITIONS( -std=c++0x )
|
||||
ADD_DEFINITIONS( -D_GLIBCXX_USE_NANOSLEEP )
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
add_compile_options(/W4)
|
||||
ELSE()
|
||||
add_compile_options(-Wall -Werror)
|
||||
ENDIF()
|
||||
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
|
||||
ADD_COMPILE_DEFINITIONS(_UPROFILE_BUILD_SHARED)
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-D_UPROFILE_BUILD_SHARED)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(PROFILE_ENABLED)
|
||||
IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
|
||||
ADD_COMPILE_DEFINITIONS(PROFILE_ON)
|
||||
ADD_DEFINITIONS( -DPROFILE_ON )
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-DPROFILE_ON)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET(UProfile_PUBLIC_HEADERS
|
||||
api.h
|
||||
uprofile.h
|
||||
timestampunit.h
|
||||
igpumonitor.h
|
||||
)
|
||||
|
||||
SET(UProfile_IMPL
|
||||
uprofile.cpp
|
||||
uprofileimpl.cpp
|
||||
util/timer.cpp
|
||||
util/cpumonitor.cpp
|
||||
)
|
||||
|
||||
IF(GPU_MONITOR_NVIDIA)
|
||||
LIST(APPEND UProfile_PUBLIC_HEADERS monitors/nvidiamonitor.h)
|
||||
LIST(APPEND UProfile_IMPL monitors/nvidiamonitor.cpp)
|
||||
ENDIF()
|
||||
|
||||
SET(UProfile_HEADERS
|
||||
${UProfile_PUBLIC_HEADERS}
|
||||
uprofileimpl.h
|
||||
util/timer.h
|
||||
util/cpumonitor.h
|
||||
)
|
||||
|
||||
SET(UProfile_SRCS
|
||||
${UProfile_HEADERS}
|
||||
${UProfile_IMPL}
|
||||
)
|
||||
|
||||
SET(LIBRARY_NAME ${PROJECT_NAME})
|
||||
|
||||
ADD_LIBRARY(${LIBRARY_NAME} ${UProfile_SRCS}) # STATIC or SHARED are determined through BUILD_SHARED_LIBS flag
|
||||
|
||||
IF(BUILD_SHARED_LIBS AND UNIX)
|
||||
# Hide symbols not explicitly tagged for export from the shared library
|
||||
TARGET_COMPILE_OPTIONS(${LIBRARY_NAME} PRIVATE "-fvisibility=hidden")
|
||||
ENDIF()
|
||||
|
||||
|
||||
# Specify the include directories exported by this library
|
||||
TARGET_INCLUDE_DIRECTORIES(${LIBRARY_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(${LIBRARY_NAME} pthread)
|
||||
ENDIF()
|
||||
|
||||
# Set specific pkg-config variables
|
||||
SET(PKG_CONFIG_LIBDIR
|
||||
"\${prefix}/lib"
|
||||
)
|
||||
SET(PKG_CONFIG_INCLUDEDIR
|
||||
"\${prefix}/include/${LIBRARY_NAME}"
|
||||
)
|
||||
SET(PKG_CONFIG_LIBS
|
||||
"-L\${libdir} -l${LIBRARY_NAME}"
|
||||
)
|
||||
SET(PKG_CONFIG_CFLAGS
|
||||
"-I\${includedir}"
|
||||
)
|
||||
|
||||
# Generate the pkg-config file
|
||||
CONFIGURE_FILE(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/pkg-config.pc.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||
)
|
||||
|
||||
# Install library project files
|
||||
INSTALL(FILES ${UProfile_PUBLIC_HEADERS}
|
||||
DESTINATION include/${LIBRARY_NAME}
|
||||
)
|
||||
INSTALL(TARGETS ${LIBRARY_NAME}
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
31
3party/cppuprofile/lib/api.h
Normal file
31
3party/cppuprofile/lib/api.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#pragma once
|
||||
|
||||
// UPROFAPI is used to export public API functions from the DLL / shared library.
|
||||
#if defined(_UPROFILE_BUILD_SHARED)
|
||||
#if defined(_WIN32)
|
||||
/* Build as a Win32 DLL */
|
||||
#define UPROFAPI __declspec(dllexport)
|
||||
#elif defined(__linux__)
|
||||
/* Build as a shared library */
|
||||
#define UPROFAPI __attribute__((visibility("default")))
|
||||
#endif // if defined(_UPROFILE_BUILD_SHARED)
|
||||
|
||||
#elif defined(UPROFILE_DLL)
|
||||
#if defined(_WIN32)
|
||||
/* Call uprofile as a Win32 DLL */
|
||||
#define UPROFAPI __declspec(dllimport)
|
||||
#endif // if defined(_WIN32)
|
||||
#endif // if defined(UPROFILE_DLL)
|
||||
|
||||
#if !defined(UPROFAPI)
|
||||
#define UPROFAPI
|
||||
#endif
|
44
3party/cppuprofile/lib/igpumonitor.h
Normal file
44
3party/cppuprofile/lib/igpumonitor.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef IGPUMONITOR_H_
|
||||
#define IGPUMONITOR_H_
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
|
||||
/**
|
||||
* Interface to implement for monitoring GPU usage and memory
|
||||
*
|
||||
* No generic abstraction of GPU metrics exists
|
||||
* on Linux nor Windows. So specific IGPUMonitor class should
|
||||
* be defined to retrieve metrics from GPU vendor (Nvidia, AMD, Broadcom
|
||||
* for RPI...)
|
||||
*/
|
||||
class IGPUMonitor
|
||||
{
|
||||
public:
|
||||
virtual ~IGPUMonitor() {}
|
||||
|
||||
// Start monitoring
|
||||
virtual void start(int period) = 0;
|
||||
// Stop monitoring
|
||||
virtual void stop() = 0;
|
||||
// Return if monitor is currently watching data
|
||||
virtual bool watching() const = 0;
|
||||
|
||||
// Usage should be in percentage
|
||||
virtual float getUsage() const = 0;
|
||||
// usedMem and totalMem should be returned as KiB
|
||||
virtual void getMemory(int& usedMem, int& totalMem) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* IGPUMONITOR_H_ */
|
171
3party/cppuprofile/lib/monitors/nvidiamonitor.cpp
Normal file
171
3party/cppuprofile/lib/monitors/nvidiamonitor.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#include "nvidiamonitor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
const string errorMsg = "Failed to monitor nvidia-smi process";
|
||||
|
||||
#if defined(__linux__)
|
||||
int read_nvidia_smi_stdout(int fd, string& gpuUsage, string& usedMem, string& totalMem)
|
||||
{
|
||||
string line;
|
||||
while (line.find('\n') == string::npos) { // full line read
|
||||
char buffer[4096];
|
||||
ssize_t count = read(fd, buffer, sizeof(buffer)); // if child process crashes, we gonna be blocked here forever
|
||||
if (count == -1) {
|
||||
return errno;
|
||||
} else if (count > 0) { // there is something to read
|
||||
line += string(buffer, count);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove colon to have only spaces and use istringstream
|
||||
auto noSpaceEnd = remove(line.begin(), line.end(), ',');
|
||||
if (noSpaceEnd == line.end()) { // output trace does not have comma so something went wrong with the command
|
||||
return ENODATA;
|
||||
}
|
||||
|
||||
line.erase(noSpaceEnd, line.end());
|
||||
std::istringstream ss(line);
|
||||
ss >> gpuUsage >> usedMem >> totalMem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
uprofile::NvidiaMonitor::NvidiaMonitor()
|
||||
{
|
||||
}
|
||||
|
||||
uprofile::NvidiaMonitor::~NvidiaMonitor()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void uprofile::NvidiaMonitor::start(int period)
|
||||
{
|
||||
watchGPU(period);
|
||||
}
|
||||
|
||||
void uprofile::NvidiaMonitor::stop()
|
||||
{
|
||||
abortWatchGPU();
|
||||
}
|
||||
|
||||
float uprofile::NvidiaMonitor::getUsage() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_gpuUsage;
|
||||
}
|
||||
|
||||
void uprofile::NvidiaMonitor::getMemory(int& usedMem, int& totalMem) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
usedMem = m_usedMem;
|
||||
totalMem = m_totalMem;
|
||||
}
|
||||
|
||||
void uprofile::NvidiaMonitor::watchGPU(int period)
|
||||
{
|
||||
if (m_watching) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
char* args[5];
|
||||
args[0] = (char*)"/usr/bin/nvidia-smi";
|
||||
string period_arg = "-lms=" + to_string(period); // lms stands for continuous watching
|
||||
args[1] = (char*)period_arg.c_str();
|
||||
args[2] = (char*)"--query-gpu=utilization.gpu,memory.used,memory.total";
|
||||
args[3] = (char*)"--format=csv,noheader,nounits";
|
||||
args[4] = NULL;
|
||||
string output;
|
||||
int pipes[2];
|
||||
|
||||
// Create the pipe
|
||||
if (pipe(pipes) == -1) {
|
||||
cerr << errorMsg << ": pipe creation failed" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a child process for calling nvidia-smi
|
||||
pid_t pid = fork();
|
||||
|
||||
switch (pid) {
|
||||
case -1: /* Error */
|
||||
cerr << errorMsg << ": process fork failed" << endl;
|
||||
return;
|
||||
case 0: /* We are in the child process */
|
||||
while ((dup2(pipes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {
|
||||
}
|
||||
close(pipes[1]);
|
||||
close(pipes[0]);
|
||||
execv(args[0], args);
|
||||
cerr << "Failed to execute '" << args[0] << "': " << strerror(errno) << endl; /* execl doesn't return unless there's an error */
|
||||
exit(1);
|
||||
default: /* We are in the parent process */
|
||||
int stdout_fd = pipes[0];
|
||||
|
||||
// Start a thread to retrieve the child process stdout
|
||||
m_watching = true;
|
||||
m_watcherThread = unique_ptr<std::thread>(new thread([stdout_fd, pid, this]() {
|
||||
while (watching()) {
|
||||
string gpuUsage, usedMem, totalMem;
|
||||
// if the child process crashes, an error is raised here and threads ends up
|
||||
int err = read_nvidia_smi_stdout(stdout_fd, gpuUsage, usedMem, totalMem);
|
||||
if (err != 0) {
|
||||
cerr << errorMsg << ": read_error = " << strerror(err) << endl;
|
||||
m_mutex.lock();
|
||||
m_watching = false;
|
||||
m_mutex.unlock();
|
||||
break;
|
||||
}
|
||||
m_mutex.lock();
|
||||
m_gpuUsage = !gpuUsage.empty() ? stof(gpuUsage) : 0.f;
|
||||
m_usedMem = !usedMem.empty() ? stoi(usedMem) * 1024 : 0; // MiB to KiB
|
||||
m_totalMem = !totalMem.empty() ? stoi(totalMem) * 1024 : 0; // MiB to KiB
|
||||
m_mutex.unlock();
|
||||
}
|
||||
}));
|
||||
}
|
||||
#else
|
||||
cerr << errorMsg << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uprofile::NvidiaMonitor::abortWatchGPU()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
if (m_watcherThread) {
|
||||
m_mutex.lock();
|
||||
m_watching = false;
|
||||
m_mutex.unlock();
|
||||
m_watcherThread->join();
|
||||
m_watcherThread.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool uprofile::NvidiaMonitor::watching() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_watching;
|
||||
}
|
49
3party/cppuprofile/lib/monitors/nvidiamonitor.h
Normal file
49
3party/cppuprofile/lib/monitors/nvidiamonitor.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef NVIDIAMONITOR_H_
|
||||
#define NVIDIAMONITOR_H_
|
||||
|
||||
#include "api.h"
|
||||
#include "igpumonitor.h"
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
class NvidiaMonitor : public IGPUMonitor
|
||||
{
|
||||
public:
|
||||
UPROFAPI explicit NvidiaMonitor();
|
||||
UPROFAPI virtual ~NvidiaMonitor();
|
||||
|
||||
UPROFAPI void start(int period) override;
|
||||
UPROFAPI void stop() override;
|
||||
UPROFAPI bool watching() const override;
|
||||
UPROFAPI float getUsage() const override;
|
||||
UPROFAPI void getMemory(int& usedMem, int& totalMem) const override;
|
||||
|
||||
private:
|
||||
void watchGPU(int period);
|
||||
void abortWatchGPU();
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
std::unique_ptr<std::thread> m_watcherThread;
|
||||
bool m_watching = false;
|
||||
int m_totalMem = 0;
|
||||
int m_usedMem = 0;
|
||||
float m_gpuUsage = 0.f;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* NVIDIAMONITOR_H_ */
|
8
3party/cppuprofile/lib/pkg-config.pc.cmake
Normal file
8
3party/cppuprofile/lib/pkg-config.pc.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
Name: ${PROJECT_NAME}
|
||||
Description: ${PROJECT_DESCRIPTION}
|
||||
Version: ${PROJECT_VERSION}
|
||||
prefix=${CMAKE_INSTALL_PREFIX}
|
||||
includedir=${PKG_CONFIG_INCLUDEDIR}
|
||||
libdir=${PKG_CONFIG_LIBDIR}
|
||||
Libs: ${PKG_CONFIG_LIBS}
|
||||
Cflags: ${PKG_CONFIG_CFLAGS}
|
23
3party/cppuprofile/lib/timestampunit.h
Normal file
23
3party/cppuprofile/lib/timestampunit.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef TIMESTAMP_UNIT_H_
|
||||
#define TIMESTAMP_UNIT_H_
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
|
||||
enum class TimestampUnit {
|
||||
EPOCH_TIME, // Time since epoch
|
||||
UPTIME // Time since boot
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* TIMESTAMP_UNIT_H_ */
|
113
3party/cppuprofile/lib/uprofile.cpp
Normal file
113
3party/cppuprofile/lib/uprofile.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "uprofile.h"
|
||||
#include "uprofileimpl.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
#ifdef PROFILE_ON
|
||||
#define UPROFILE_INSTANCE_CALL(func, ...) \
|
||||
UProfileImpl::getInstance()->func(__VA_ARGS__);
|
||||
#define UPROFILE_INSTANCE_CALL_RETURN(func, ...) \
|
||||
return UProfileImpl::getInstance()->func(__VA_ARGS__);
|
||||
#define UPROFILE_DESTROY_INSTANCE() \
|
||||
UProfileImpl::destroyInstance();
|
||||
#else
|
||||
#define UPROFILE_INSTANCE_CALL(func, ...) (void)0;
|
||||
#define UPROFILE_INSTANCE_CALL_RETURN(func, ...) \
|
||||
return {}
|
||||
#define UPROFILE_DESTROY_INSTANCE() (void)0;
|
||||
#endif
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
|
||||
void start(const char* file)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(start, file);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(stop);
|
||||
UPROFILE_DESTROY_INSTANCE();
|
||||
}
|
||||
|
||||
void addGPUMonitor(IGPUMonitor* monitor)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(addGPUMonitor, monitor);
|
||||
}
|
||||
|
||||
void removeGPUMonitor()
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(removeGPUMonitor);
|
||||
}
|
||||
|
||||
void setTimestampUnit(TimestampUnit tsUnit)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(setTimestampUnit, tsUnit);
|
||||
}
|
||||
|
||||
void timeBegin(const std::string& step)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(timeBegin, step);
|
||||
}
|
||||
|
||||
void timeEnd(const std::string& step)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(timeEnd, step);
|
||||
}
|
||||
|
||||
void startProcessMemoryMonitoring(int period)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(startProcessMemoryMonitoring, period);
|
||||
}
|
||||
|
||||
void startSystemMemoryMonitoring(int period)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(startSystemMemoryMonitoring, period);
|
||||
}
|
||||
|
||||
void startCPUUsageMonitoring(int period)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(startCPUUsageMonitoring, period);
|
||||
}
|
||||
|
||||
void startGPUUsageMonitoring(int period)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(startGPUUsageMonitoring, period);
|
||||
}
|
||||
|
||||
void startGPUMemoryMonitoring(int period)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(startGPUMemoryMonitoring, period);
|
||||
}
|
||||
|
||||
void getProcessMemory(int& rss, int& shared)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(getProcessMemory, rss, shared);
|
||||
}
|
||||
|
||||
void getSystemMemory(int& totalMem, int& availableMem, int& freeMem)
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL(getSystemMemory, totalMem, availableMem, freeMem);
|
||||
}
|
||||
|
||||
std::vector<float> getInstantCpuUsage()
|
||||
{
|
||||
UPROFILE_INSTANCE_CALL_RETURN(getInstantCpuUsage);
|
||||
}
|
||||
|
||||
}
|
142
3party/cppuprofile/lib/uprofile.h
Normal file
142
3party/cppuprofile/lib/uprofile.h
Normal file
@@ -0,0 +1,142 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef UPROFILE_H_
|
||||
#define UPROFILE_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api.h"
|
||||
#include "igpumonitor.h"
|
||||
#include "timestampunit.h"
|
||||
|
||||
/**
|
||||
* @defgroup uprofile Functions for monitoring system metrics
|
||||
* @{
|
||||
*/
|
||||
namespace uprofile
|
||||
{
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start profiling to periodically record monitored events to a file
|
||||
* @param file: file path where events will be saved
|
||||
*/
|
||||
UPROFAPI void start(const char* file);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Stop all monitorings
|
||||
*
|
||||
* Note: stopping profiler without prior call to start() has no effect
|
||||
*/
|
||||
UPROFAPI void stop();
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Inject a GPUMonitor object that will be responsible for monitoring GPU metrics (usage and memory)
|
||||
* @param monitor: custom GPUMonitor object
|
||||
*
|
||||
* Note: uprofile takes ownership of the passed object.
|
||||
*/
|
||||
UPROFAPI void addGPUMonitor(IGPUMonitor* monitor);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Destroy injected GPUMonitor object
|
||||
*/
|
||||
UPROFAPI void removeGPUMonitor();
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Change the timestamp unit to record profiling metrics
|
||||
*
|
||||
* It should be called before calling start() method.
|
||||
*
|
||||
* Note: default value is EPOCH_TIME
|
||||
*/
|
||||
UPROFAPI void setTimestampUnit(TimestampUnit tsUnit);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring the execution time of the given event
|
||||
* @param title: event key
|
||||
*/
|
||||
UPROFAPI void timeBegin(const std::string& title);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Stop monitoring the execution time of the given event
|
||||
*
|
||||
* The library computes the duration for the given event and saves it into the report file.
|
||||
*
|
||||
* If no timeBegin() has been called with the given title, the call is ignored.
|
||||
*/
|
||||
UPROFAPI void timeEnd(const std::string& title);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring of the memory used by the process
|
||||
* @param period: period between two memory dump (in ms)
|
||||
*/
|
||||
UPROFAPI void startProcessMemoryMonitoring(int period);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring of the global memory used on the system
|
||||
* @param period: period between two memory dump (in ms)
|
||||
*/
|
||||
UPROFAPI void startSystemMemoryMonitoring(int period);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring of the usage percentage of each CPU
|
||||
* @param period: period between two cpu usage dump (in ms)
|
||||
*/
|
||||
UPROFAPI void startCPUUsageMonitoring(int period);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring of the usage of the GPU
|
||||
* @param period: period between two gpu usage dump (in ms)
|
||||
*/
|
||||
UPROFAPI void startGPUUsageMonitoring(int period);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief Start monitoring of the usage of the GPU memory
|
||||
* @param period: period between two gpu usage dump (in ms)
|
||||
*/
|
||||
UPROFAPI void startGPUMemoryMonitoring(int period);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief memory used by the current process
|
||||
*/
|
||||
UPROFAPI void getProcessMemory(int& rss, int& shared);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief dump global system memory
|
||||
*/
|
||||
UPROFAPI void getSystemMemory(int& totalMem, int& availableMem, int& freeMem);
|
||||
|
||||
/**
|
||||
* @ingroup uprofile
|
||||
* @brief get usage of all cpu cores
|
||||
* @return vector holding the usage percentage of each CPU core
|
||||
*/
|
||||
UPROFAPI std::vector<float> getInstantCpuUsage();
|
||||
}
|
||||
/** @} */ // end of uprofile group
|
||||
|
||||
#endif /* UPROFILE_H_ */
|
353
3party/cppuprofile/lib/uprofileimpl.cpp
Normal file
353
3party/cppuprofile/lib/uprofileimpl.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/sysinfo.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "uprofileimpl.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace uprofile {
|
||||
|
||||
UProfileImpl *UProfileImpl::m_uprofiler = NULL;
|
||||
|
||||
UProfileImpl::UProfileImpl() : m_tsUnit(TimestampUnit::EPOCH_TIME), m_gpuMonitor(NULL) {}
|
||||
|
||||
UProfileImpl *
|
||||
UProfileImpl::getInstance()
|
||||
{
|
||||
if (!m_uprofiler) { m_uprofiler = new UProfileImpl; }
|
||||
return m_uprofiler;
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::destroyInstance()
|
||||
{
|
||||
delete m_uprofiler;
|
||||
m_uprofiler = NULL;
|
||||
}
|
||||
|
||||
UProfileImpl::~UProfileImpl() { removeGPUMonitor(); }
|
||||
|
||||
void
|
||||
UProfileImpl::start(const char *file)
|
||||
{
|
||||
m_file.open(file, std::ios::out);
|
||||
if (!m_file.is_open()) { std::cerr << "Failed to open file: " << file << std::endl; }
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::addGPUMonitor(IGPUMonitor *monitor)
|
||||
{
|
||||
if (!monitor) {
|
||||
std::cerr << "Invalid GPU Monitor" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_gpuMonitor) { removeGPUMonitor(); }
|
||||
|
||||
m_gpuMonitor = monitor;
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::removeGPUMonitor()
|
||||
{
|
||||
delete m_gpuMonitor;
|
||||
m_gpuMonitor = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::timeBegin(const std::string &title)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_stepsMutex);
|
||||
m_steps.insert(make_pair(title, getTimestamp()));
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::timeEnd(const std::string &title)
|
||||
{
|
||||
unsigned long long beginTimestamp = 0;
|
||||
|
||||
// Find step in the map
|
||||
m_stepsMutex.lock();
|
||||
auto it = m_steps.find(title);
|
||||
bool found = it != m_steps.end();
|
||||
if (found) {
|
||||
beginTimestamp = (*it).second;
|
||||
m_steps.erase(it);
|
||||
}
|
||||
m_stepsMutex.unlock();
|
||||
|
||||
if (found) {
|
||||
write(ProfilingType::TIME_EXEC, {std::to_string(beginTimestamp), title});
|
||||
} else {
|
||||
write(ProfilingType::TIME_EVENT, {title});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::startProcessMemoryMonitoring(int period)
|
||||
{
|
||||
m_processMemoryMonitorTimer.setInterval(period);
|
||||
m_processMemoryMonitorTimer.setTimeout([=]() { dumpProcessMemory(); });
|
||||
m_processMemoryMonitorTimer.start();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::startSystemMemoryMonitoring(int period)
|
||||
{
|
||||
m_systemMemoryMonitorTimer.setInterval(period);
|
||||
m_systemMemoryMonitorTimer.setTimeout([=]() { dumpSystemMemory(); });
|
||||
m_systemMemoryMonitorTimer.start();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::startCPUUsageMonitoring(int period)
|
||||
{
|
||||
m_cpuMonitorTimer.setInterval(period);
|
||||
m_cpuMonitorTimer.setTimeout([=]() { dumpCpuUsage(); });
|
||||
m_cpuMonitorTimer.start();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::startGPUUsageMonitoring(int period)
|
||||
{
|
||||
if (!m_gpuMonitor) {
|
||||
std::cerr << "Cannot monitor GPU usage: no GPUMonitor set!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_gpuMonitor->start(period);
|
||||
|
||||
m_gpuUsageMonitorTimer.setInterval(period);
|
||||
m_gpuUsageMonitorTimer.setTimeout([=]() { dumpGpuUsage(); });
|
||||
m_gpuUsageMonitorTimer.start();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::startGPUMemoryMonitoring(int period)
|
||||
{
|
||||
if (!m_gpuMonitor) {
|
||||
std::cerr << "Cannot monitor GPU memory: no GPUMonitor set!" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_gpuMonitor->start(period);
|
||||
|
||||
m_gpuMemoryMonitorTimer.setInterval(period);
|
||||
m_gpuMemoryMonitorTimer.setTimeout([=]() { dumpGpuMemory(); });
|
||||
m_gpuMemoryMonitorTimer.start();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::dumpProcessMemory()
|
||||
{
|
||||
int rss = 0, shared = 0;
|
||||
getProcessMemory(rss, shared);
|
||||
write(ProfilingType::PROCESS_MEMORY, {std::to_string(rss), std::to_string(shared)});
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::dumpSystemMemory()
|
||||
{
|
||||
int total = 0, available = 0, free = 0;
|
||||
getSystemMemory(total, available, free);
|
||||
write(ProfilingType::SYSTEM_MEMORY, {std::to_string(total), std::to_string(available), std::to_string(free)});
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::dumpCpuUsage()
|
||||
{
|
||||
vector<float> cpuLoads = m_cpuMonitor.getUsage();
|
||||
for (size_t index = 0; index < cpuLoads.size(); ++index) {
|
||||
write(ProfilingType::CPU, {std::to_string(index), std::to_string(cpuLoads.at(index))});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::dumpGpuUsage()
|
||||
{
|
||||
if (!m_gpuMonitor || !m_gpuMonitor->watching()) { return; }
|
||||
|
||||
float usage = m_gpuMonitor->getUsage();
|
||||
write(ProfilingType::GPU_USAGE, {std::to_string(usage)});
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::dumpGpuMemory()
|
||||
{
|
||||
if (!m_gpuMonitor || !m_gpuMonitor->watching()) { return; }
|
||||
|
||||
int usedMem, totalMem;
|
||||
m_gpuMonitor->getMemory(usedMem, totalMem);
|
||||
write(ProfilingType::GPU_MEMORY, {std::to_string(usedMem), std::to_string(totalMem)});
|
||||
}
|
||||
|
||||
vector<float>
|
||||
UProfileImpl::getInstantCpuUsage()
|
||||
{
|
||||
// To get instaneous CPU usage, we should wait at least one unit between two polling (aka: 100 ms)
|
||||
m_cpuMonitor.getUsage();
|
||||
this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
return m_cpuMonitor.getUsage();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::stop()
|
||||
{
|
||||
m_processMemoryMonitorTimer.stop();
|
||||
m_systemMemoryMonitorTimer.stop();
|
||||
m_cpuMonitorTimer.stop();
|
||||
m_gpuUsageMonitorTimer.stop();
|
||||
m_gpuMemoryMonitorTimer.stop();
|
||||
if (m_gpuMonitor) { m_gpuMonitor->stop(); }
|
||||
m_file.close();
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::setTimestampUnit(TimestampUnit tsUnit)
|
||||
{
|
||||
m_tsUnit = tsUnit;
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::write(ProfilingType type, const std::list<std::string> &data)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_fileMutex);
|
||||
if (m_file.is_open()) {
|
||||
const char csvSeparator = ';';
|
||||
std::string strType;
|
||||
switch (type) {
|
||||
case ProfilingType::TIME_EXEC:
|
||||
strType = "time_exec";
|
||||
break;
|
||||
case ProfilingType::TIME_EVENT:
|
||||
strType = "time_event";
|
||||
break;
|
||||
case ProfilingType::PROCESS_MEMORY:
|
||||
strType = "proc_mem";
|
||||
break;
|
||||
case ProfilingType::SYSTEM_MEMORY:
|
||||
strType = "sys_mem";
|
||||
break;
|
||||
case ProfilingType::CPU:
|
||||
strType = "cpu";
|
||||
break;
|
||||
case ProfilingType::GPU_USAGE:
|
||||
strType = "gpu";
|
||||
break;
|
||||
case ProfilingType::GPU_MEMORY:
|
||||
strType = "gpu_mem";
|
||||
break;
|
||||
default:
|
||||
strType = "undefined";
|
||||
break;
|
||||
}
|
||||
m_file << strType.c_str() << csvSeparator << getTimestamp();
|
||||
for (auto it = data.cbegin(); it != data.cend(); ++it) { m_file << csvSeparator << *it; }
|
||||
m_file << "\n";
|
||||
m_file.flush();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
UProfileImpl::getTimestamp() const
|
||||
{
|
||||
return (m_tsUnit == TimestampUnit::EPOCH_TIME ? getEpochTime() : getTimeSinceBoot());
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
UProfileImpl::getEpochTime()
|
||||
{
|
||||
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
UProfileImpl::getTimeSinceBoot()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
double uptime_seconds;
|
||||
if (std::ifstream("/proc/uptime", std::ios::in) >> uptime_seconds) {
|
||||
return static_cast<unsigned long long>(uptime_seconds * 1000.0);
|
||||
}
|
||||
return 0;
|
||||
#elif defined(_WIN32)
|
||||
return GetTickCount64();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::getSystemMemory(int &totalMem, int &availableMem, int &freeMem)
|
||||
{
|
||||
|
||||
#if defined(__linux__)
|
||||
// /proc/meminfo returns the dump here:
|
||||
// MemTotal: 515164 kB
|
||||
// MemFree: 7348 kB
|
||||
// MemAvailable: 7348 kB
|
||||
ifstream meminfo("/proc/meminfo");
|
||||
string line;
|
||||
while (std::getline(meminfo, line)) {
|
||||
if (line.find("MemTotal") != std::string::npos) {
|
||||
stringstream ls(line);
|
||||
ls.ignore(256, ' ');
|
||||
ls >> totalMem;
|
||||
} else if (line.find("MemFree") != std::string::npos) {
|
||||
stringstream ls(line);
|
||||
ls.ignore(256, ' ');
|
||||
ls >> freeMem;
|
||||
} else if (line.find("MemAvailable") != std::string::npos) {
|
||||
{
|
||||
stringstream ls(line);
|
||||
ls.ignore(256, ' ');
|
||||
ls >> availableMem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
UProfileImpl::getProcessMemory(int &rss, int &shared)
|
||||
{
|
||||
|
||||
#if defined(__linux__)
|
||||
int tSize = 0, resident = 0, share = 0;
|
||||
ifstream buffer("/proc/self/statm");
|
||||
buffer >> tSize >> resident >> share;
|
||||
buffer.close();
|
||||
|
||||
long page_size_kb = getpagesize() / 1024;
|
||||
rss = resident * page_size_kb;
|
||||
shared = share * page_size_kb;
|
||||
#elif defined(__APPLE__)
|
||||
struct rusage usage;
|
||||
if (0 == getrusage(RUSAGE_SELF, &usage)) {
|
||||
rss = usage.ru_maxrss;
|
||||
shared = usage.ru_ixrss;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}// namespace uprofile
|
91
3party/cppuprofile/lib/uprofileimpl.h
Normal file
91
3party/cppuprofile/lib/uprofileimpl.h
Normal file
@@ -0,0 +1,91 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef UPROFILEIMPL_H_
|
||||
#define UPROFILEIMPL_H_
|
||||
|
||||
#include "igpumonitor.h"
|
||||
#include "timestampunit.h"
|
||||
#include "util/cpumonitor.h"
|
||||
#include "util/timer.h"
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
class UProfileImpl
|
||||
{
|
||||
public:
|
||||
enum class ProfilingType {
|
||||
TIME_EXEC,
|
||||
TIME_EVENT,
|
||||
PROCESS_MEMORY,
|
||||
SYSTEM_MEMORY,
|
||||
CPU,
|
||||
GPU_USAGE,
|
||||
GPU_MEMORY
|
||||
};
|
||||
|
||||
static UProfileImpl* getInstance();
|
||||
static void destroyInstance();
|
||||
virtual ~UProfileImpl();
|
||||
|
||||
// Implementation
|
||||
void start(const char* file);
|
||||
void stop();
|
||||
void addGPUMonitor(IGPUMonitor* monitor);
|
||||
void removeGPUMonitor();
|
||||
void setTimestampUnit(TimestampUnit tsUnit);
|
||||
void timeBegin(const std::string& title);
|
||||
void timeEnd(const std::string& title);
|
||||
void startProcessMemoryMonitoring(int period);
|
||||
void startSystemMemoryMonitoring(int period);
|
||||
void startCPUUsageMonitoring(int period);
|
||||
void startGPUUsageMonitoring(int period);
|
||||
void startGPUMemoryMonitoring(int period);
|
||||
void getProcessMemory(int& rss, int& shared);
|
||||
void getSystemMemory(int& totalMem, int& availableMem, int& freeMem);
|
||||
vector<float> getInstantCpuUsage();
|
||||
|
||||
private:
|
||||
static UProfileImpl* m_uprofiler;
|
||||
UProfileImpl();
|
||||
|
||||
void write(ProfilingType type, const std::list<std::string>& data);
|
||||
unsigned long long getTimestamp() const;
|
||||
static unsigned long long getEpochTime();
|
||||
static unsigned long long getTimeSinceBoot();
|
||||
|
||||
void dumpCpuUsage();
|
||||
void dumpProcessMemory();
|
||||
void dumpSystemMemory();
|
||||
void dumpGpuUsage();
|
||||
void dumpGpuMemory();
|
||||
|
||||
TimestampUnit m_tsUnit;
|
||||
std::map<std::string, unsigned long long> m_steps; // Store steps (title, start time)
|
||||
std::ofstream m_file;
|
||||
Timer m_processMemoryMonitorTimer;
|
||||
Timer m_systemMemoryMonitorTimer;
|
||||
Timer m_cpuMonitorTimer;
|
||||
Timer m_gpuUsageMonitorTimer;
|
||||
Timer m_gpuMemoryMonitorTimer;
|
||||
CpuMonitor m_cpuMonitor;
|
||||
IGPUMonitor* m_gpuMonitor;
|
||||
|
||||
std::mutex m_fileMutex;
|
||||
std::mutex m_stepsMutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* UPROFILEIMPL_H_ */
|
100
3party/cppuprofile/lib/util/cpumonitor.cpp
Normal file
100
3party/cppuprofile/lib/util/cpumonitor.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#include "cpumonitor.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
uprofile::CpuMonitor::CpuMonitor() :
|
||||
m_nbCpus(getNumberOfCPUCores())
|
||||
{
|
||||
m_lastIdleTimes.resize(m_nbCpus, 0);
|
||||
m_lastTotalTimes.resize(m_nbCpus, 0);
|
||||
}
|
||||
|
||||
uprofile::CpuMonitor::~CpuMonitor()
|
||||
{
|
||||
}
|
||||
|
||||
size_t uprofile::CpuMonitor::getNumberOfCPUCores()
|
||||
{
|
||||
size_t nbCores = 0;
|
||||
#if defined(__linux__)
|
||||
ifstream meminfo("/proc/cpuinfo");
|
||||
string str;
|
||||
while (getline(meminfo, str)) {
|
||||
if (str.rfind("processor", 0) == 0) {
|
||||
nbCores++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return nbCores;
|
||||
}
|
||||
|
||||
void uprofile::CpuMonitor::extractCpuTimes(const string& cpuInfo, size_t& idleTime, size_t& totalTime)
|
||||
{
|
||||
// Remove 'cpu<index' word and
|
||||
// extract the idle time and sum all other times
|
||||
size_t spacePos = cpuInfo.find(' ');
|
||||
if (spacePos == string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
stringstream times(cpuInfo.substr(spacePos + 1));
|
||||
int index = 0;
|
||||
for (size_t time; times >> time; ++index) {
|
||||
if (index == 3) { // idle time i s the 4th param
|
||||
idleTime = time;
|
||||
}
|
||||
totalTime += time;
|
||||
}
|
||||
}
|
||||
|
||||
vector<float> uprofile::CpuMonitor::getUsage()
|
||||
{
|
||||
vector<float> usages;
|
||||
#if defined(__linux__)
|
||||
ifstream procStat("/proc/stat");
|
||||
// /proc/stat dumps the following info:
|
||||
// user nice system idle iowait irq softirq
|
||||
// cpu 2255 34 2290 22625563 6290 127 456
|
||||
// cpu0 1132 34 1441 11311718 3675 127 438
|
||||
// cpu1 1123 0 849 11313845 2614 0 18
|
||||
// ...
|
||||
// Each numbers represents the amount of time the CPU has spent performing
|
||||
// different kind of work
|
||||
|
||||
for (size_t cpuIndex = 0; cpuIndex < m_nbCpus; ++cpuIndex) {
|
||||
string cpuName("cpu");
|
||||
cpuName += to_string(cpuIndex);
|
||||
|
||||
// Look in /proc/stack the CPU info
|
||||
string line;
|
||||
while (getline(procStat, line)) {
|
||||
if (line.find(cpuName) != std::string::npos) {
|
||||
size_t idleTime = 0, totalTime = 0;
|
||||
extractCpuTimes(line, idleTime, totalTime);
|
||||
|
||||
// To compute CPU load, we compute the time the CPU has been idle since the last read.
|
||||
float cpuLoad = 100.0 * (1.0 - (float)(idleTime - m_lastIdleTimes[cpuIndex]) / (totalTime - m_lastTotalTimes[cpuIndex]));
|
||||
usages.push_back(cpuLoad);
|
||||
|
||||
// Save the times value for the next read
|
||||
m_lastIdleTimes[cpuIndex] = idleTime;
|
||||
m_lastTotalTimes[cpuIndex] = totalTime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return usages;
|
||||
}
|
41
3party/cppuprofile/lib/util/cpumonitor.h
Normal file
41
3party/cppuprofile/lib/util/cpumonitor.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef CPUMONITOR_H_
|
||||
#define CPUMONITOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace uprofile
|
||||
{
|
||||
|
||||
class CpuMonitor
|
||||
{
|
||||
public:
|
||||
explicit CpuMonitor();
|
||||
virtual ~CpuMonitor();
|
||||
|
||||
vector<float> getUsage();
|
||||
|
||||
private:
|
||||
static size_t getNumberOfCPUCores();
|
||||
static void extractCpuTimes(const string& cpuInfo, size_t& idleTime, size_t& totalTime);
|
||||
|
||||
// Store the last idle and total time for each CPU
|
||||
vector<size_t> m_lastIdleTimes;
|
||||
vector<size_t> m_lastTotalTimes;
|
||||
|
||||
size_t m_nbCpus;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CPUMONITOR_H_ */
|
64
3party/cppuprofile/lib/util/timer.cpp
Normal file
64
3party/cppuprofile/lib/util/timer.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
Timer::Timer(int interval) :
|
||||
m_th(NULL),
|
||||
m_interval(interval)
|
||||
{
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void Timer::setInterval(int interval)
|
||||
{
|
||||
m_interval = interval;
|
||||
}
|
||||
|
||||
void Timer::setTimeout(const std::function<void(void)>& timeout)
|
||||
{
|
||||
m_timeout = timeout;
|
||||
}
|
||||
|
||||
bool Timer::isRunning()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void Timer::start()
|
||||
{
|
||||
if (m_interval > 0 && m_th == NULL) {
|
||||
m_running = true;
|
||||
m_th = new thread([=]() {
|
||||
while (isRunning()) {
|
||||
this_thread::sleep_for(chrono::milliseconds(m_interval));
|
||||
if (m_timeout) {
|
||||
m_timeout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::stop()
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_running = false;
|
||||
m_mutex.unlock();
|
||||
if (m_th) {
|
||||
m_th->join();
|
||||
delete m_th;
|
||||
m_th = NULL;
|
||||
}
|
||||
}
|
41
3party/cppuprofile/lib/util/timer.h
Normal file
41
3party/cppuprofile/lib/util/timer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Software Name : cppuprofile
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022 Orange
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
//
|
||||
// This software is distributed under the BSD License;
|
||||
// see the LICENSE file for more details.
|
||||
//
|
||||
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al.
|
||||
|
||||
#ifndef TIMER_H_
|
||||
#define TIMER_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
explicit Timer(int interval /* ms */ = 0);
|
||||
virtual ~Timer();
|
||||
|
||||
void setTimeout(const function<void(void)>& timeout);
|
||||
void setInterval(int interval);
|
||||
void start();
|
||||
void stop();
|
||||
bool isRunning();
|
||||
|
||||
private:
|
||||
thread* m_th;
|
||||
bool m_running;
|
||||
int m_interval;
|
||||
std::mutex m_mutex;
|
||||
std::function<void(void)> m_timeout;
|
||||
};
|
||||
|
||||
#endif // TIMER_H_
|
Reference in New Issue
Block a user