Skip to content
Snippets Groups Projects
Commit 7c343eaa authored by Rosen Matev's avatar Rosen Matev :sunny:
Browse files

Add algorithm to programmatically enable/disable perf

parent db183448
No related branches found
No related tags found
1 merge request!1408Add algorithm to programmatically enable/disable perf
......@@ -111,6 +111,16 @@ gaudi_add_module(GaudiJemalloc
LINK GaudiKernel
GaudiAlgLib)
#-----------------------------------
# Linux perf
#-----------------------------------
# TODO: The PerfProfile algorithm should only be compiled for Linux
# (and consequently the test should only run if PerfProfile is there).
gaudi_add_module(GaudiPerf
SOURCES src/component/perf/PerfProfile.cpp
LINK GaudiKernel
GaudiAlgLib)
# Special handling of unresolved symbols in Jemmalloc.
# The profilers need to have libjemalloc.so pre-loaded to
# work, so it's better if the symbols stay undefined in case somebody tries to
......@@ -122,6 +132,8 @@ if(GAUDI_USE_JEMALLOC)
COMMAND run ${CMAKE_COMMAND} -E env LD_PRELOAD=$<TARGET_PROPERTY:jemalloc::jemalloc,LOCATION> gaudirun.py)
endif()
gaudi_add_tests(pytest)
# Install python modules
gaudi_install(PYTHON)
# Install other scripts
......
/***********************************************************************************\
* (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations *
* *
* This software is distributed under the terms of the Apache version 2 licence, *
* copied verbatim in the file "LICENSE". *
* *
* In applying this licence, CERN does not waive the privileges and immunities *
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\***********************************************************************************/
#include "GaudiAlg/Consumer.h"
#include <fcntl.h>
#include <string_view>
#include <sys/stat.h>
/** Algorithm to enable/disable profiling with Linux perf at given events.
*
* Needs at least perf 5.9. To control perf record, start it as
*
* perf record -D -1 --control fifo:GaudiPerfProfile.fifo ... gaudirun.py ...
*
* The path to the control fifo (GaudiPerfProfile.fifo) is configurable
* with the FIFOPath property. The fifo must be created before running perf.
*
*/
struct PerfProfile final : Gaudi::Functional::Consumer<void()> {
using Consumer::Consumer;
StatusCode initialize() override {
return Consumer::initialize().andThen( [this]() {
m_fifo = ::open( m_fifoPath.value().c_str(), O_WRONLY | O_NONBLOCK );
if ( m_fifo == -1 ) {
fatal() << "open(\"" << m_fifoPath.value() << "\"): " << ::strerror( errno ) << endmsg;
return StatusCode::FAILURE;
}
return StatusCode::SUCCESS;
} );
}
StatusCode finalize() override {
if ( m_fifo != -1 ) { ::close( m_fifo ); }
return Consumer::finalize();
}
void operator()() const override {
// We could use EventContext::evt(), however it is not always valid, as is the case with EvtSel="NONE". Instead, use
// an atomic counter.
auto eventNumber = m_eventNumber++;
if ( eventNumber == m_nStartFromEvent.value() ) {
warning() << "Starting perf profile at event " << eventNumber << endmsg;
fifo_write( "enable\n" );
}
if ( m_nStopAtEvent > 0 && eventNumber == m_nStopAtEvent.value() ) {
warning() << "Stopping perf profile at event " << eventNumber << endmsg;
fifo_write( "disable\n" );
}
}
private:
void fifo_write( std::string_view s ) const {
if ( ::write( m_fifo, s.data(), s.size() ) < ssize_t( s.size() ) ) {
error() << "Write of \"" << s << "\" to FIFO failed: " << ::strerror( errno ) << endmsg;
}
}
mutable std::atomic<long unsigned> m_eventNumber = 0;
int m_fifo = -1;
Gaudi::Property<std::string> m_fifoPath{ this, "FIFOPath", "GaudiPerfProfile.fifo", "Path to perf control FIFO." };
Gaudi::Property<unsigned long> m_nStartFromEvent{ this, "StartFromEventN", 1,
"After what event we start profiling." };
Gaudi::Property<unsigned long> m_nStopAtEvent{
this, "StopAtEventN", 0,
"After what event we stop profiling. If 0 than we also profile finalization stage. Default = 0." };
};
DECLARE_COMPONENT( PerfProfile )
#####################################################################################
# (c) Copyright 2022-2023 CERN for the benefit of the LHCb and ATLAS collaborations #
# #
# This software is distributed under the terms of the Apache version 2 licence, #
# copied verbatim in the file "LICENSE". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
#####################################################################################
import os
from threading import Thread
from GaudiTests import run_gaudi
def config():
from Configurables import ApplicationMgr, PerfProfile
prof = PerfProfile(
FIFOPath="control.fifo",
StartFromEventN=3,
StopAtEventN=8,
)
ApplicationMgr(
EvtSel="NONE",
EvtMax=10,
TopAlg=[prof],
)
def test(tmp_path):
"""Emulate perf record --control"""
fifo = tmp_path / "control.fifo"
fifo_lines = []
os.mkfifo(fifo)
def reader():
# open blocks until FIFO is opened for writing by PerfProfile::initialize(), so run it in a thread
with open(fifo) as f:
for line in f:
fifo_lines.append(line)
t = Thread(target=reader)
t.start()
run_gaudi(f"{__file__}:config", check=True, cwd=tmp_path)
t.join()
assert fifo_lines == ["enable\n", "disable\n"]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment