UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

2,159 lines (1,947 loc) 70.3 kB
"use strict"; /** * C++ Valgrind Memory Analysis Generator * Generates Valgrind configuration and memory testing tools for C++ projects */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CppValgrindGenerator = void 0; class CppValgrindGenerator { static generate(config) { const { projectName, enableMemcheck = true, enableHelgrind = true, enableCachegrind = true, enableCallgrind = false, enableMassif = true, enableDRD = false, suppressionFiles = [], customFlags = [] } = config; return { 'valgrind/valgrind.cmake': this.generateValgrindCMake(projectName), 'valgrind/memcheck.supp': this.generateMemcheckSuppressions(), 'valgrind/helgrind.supp': this.generateHelgrindSuppressions(), 'scripts/run_valgrind.sh': this.generateValgrindScript(projectName, { enableMemcheck, enableHelgrind, enableCachegrind, enableCallgrind, enableMassif, enableDRD, suppressionFiles, customFlags }), 'scripts/valgrind_analysis.py': this.generateValgrindAnalysis(), 'valgrind/README.md': this.generateValgrindReadme(projectName), '.github/workflows/valgrind.yml': this.generateValgrindCI(projectName), 'valgrind/docker/Dockerfile.valgrind': this.generateValgrindDockerfile(), 'valgrind/configs/memcheck.conf': this.generateMemcheckConfig(), 'valgrind/configs/helgrind.conf': this.generateHelgrindConfig(), 'valgrind/configs/cachegrind.conf': this.generateCachegrindConfig(), 'valgrind/configs/massif.conf': this.generateMassifConfig(), 'scripts/memory_report.py': this.generateMemoryReport() }; } static generateValgrindCMake(projectName) { return `# Valgrind Integration for ${projectName} # Memory analysis and profiling tools find_program(VALGRIND_EXECUTABLE valgrind) if(VALGRIND_EXECUTABLE) message(STATUS "Valgrind found: \${VALGRIND_EXECUTABLE}") # Valgrind configuration set(VALGRIND_COMMON_FLAGS --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --error-exitcode=1 --gen-suppressions=all --suppressions=\${CMAKE_SOURCE_DIR}/valgrind/memcheck.supp ) # Create valgrind targets for all executables function(add_valgrind_test TARGET_NAME) cmake_parse_arguments( VALGRIND "MEMCHECK;HELGRIND;CACHEGRIND;CALLGRIND;MASSIF;DRD" "WORKING_DIRECTORY;TIMEOUT" "ARGS;SUPPRESSIONS" \${ARGN} ) if(NOT VALGRIND_WORKING_DIRECTORY) set(VALGRIND_WORKING_DIRECTORY \${CMAKE_CURRENT_BINARY_DIR}) endif() if(NOT VALGRIND_TIMEOUT) set(VALGRIND_TIMEOUT 300) endif() # Memcheck (default) if(VALGRIND_MEMCHECK OR NOT (VALGRIND_HELGRIND OR VALGRIND_CACHEGRIND OR VALGRIND_CALLGRIND OR VALGRIND_MASSIF OR VALGRIND_DRD)) set(MEMCHECK_FLAGS --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --error-exitcode=1 --xml=yes --xml-file=\${CMAKE_BINARY_DIR}/valgrind_\${TARGET_NAME}_memcheck.xml --suppressions=\${CMAKE_SOURCE_DIR}/valgrind/memcheck.supp ) foreach(SUPP_FILE \${VALGRIND_SUPPRESSIONS}) list(APPEND MEMCHECK_FLAGS --suppressions=\${SUPP_FILE}) endforeach() add_test( NAME valgrind_memcheck_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${MEMCHECK_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_memcheck_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;Memcheck;Memory" ) endif() # Helgrind (thread error detection) if(VALGRIND_HELGRIND) set(HELGRIND_FLAGS --tool=helgrind --verbose --error-exitcode=1 --xml=yes --xml-file=\${CMAKE_BINARY_DIR}/valgrind_\${TARGET_NAME}_helgrind.xml --suppressions=\${CMAKE_SOURCE_DIR}/valgrind/helgrind.supp ) add_test( NAME valgrind_helgrind_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${HELGRIND_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_helgrind_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;Helgrind;Threading" ) endif() # Cachegrind (cache profiling) if(VALGRIND_CACHEGRIND) set(CACHEGRIND_FLAGS --tool=cachegrind --verbose --cachegrind-out-file=\${CMAKE_BINARY_DIR}/cachegrind_\${TARGET_NAME}.out ) add_test( NAME valgrind_cachegrind_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${CACHEGRIND_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_cachegrind_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;Cachegrind;Performance" ) endif() # Callgrind (call profiling) if(VALGRIND_CALLGRIND) set(CALLGRIND_FLAGS --tool=callgrind --verbose --callgrind-out-file=\${CMAKE_BINARY_DIR}/callgrind_\${TARGET_NAME}.out --dump-instr=yes --collect-jumps=yes ) add_test( NAME valgrind_callgrind_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${CALLGRIND_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_callgrind_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;Callgrind;Profiling" ) endif() # Massif (heap profiling) if(VALGRIND_MASSIF) set(MASSIF_FLAGS --tool=massif --verbose --massif-out-file=\${CMAKE_BINARY_DIR}/massif_\${TARGET_NAME}.out --heap=yes --stacks=yes --time-unit=ms ) add_test( NAME valgrind_massif_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${MASSIF_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_massif_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;Massif;Heap" ) endif() # DRD (data race detection) if(VALGRIND_DRD) set(DRD_FLAGS --tool=drd --verbose --error-exitcode=1 --xml=yes --xml-file=\${CMAKE_BINARY_DIR}/valgrind_\${TARGET_NAME}_drd.xml ) add_test( NAME valgrind_drd_\${TARGET_NAME} COMMAND \${VALGRIND_EXECUTABLE} \${DRD_FLAGS} \$<TARGET_FILE:\${TARGET_NAME}> \${VALGRIND_ARGS} WORKING_DIRECTORY \${VALGRIND_WORKING_DIRECTORY} ) set_tests_properties(valgrind_drd_\${TARGET_NAME} PROPERTIES TIMEOUT \${VALGRIND_TIMEOUT} LABELS "Valgrind;DRD;Threading" ) endif() endfunction() # Custom targets for comprehensive analysis add_custom_target(valgrind_all COMMENT "Running all Valgrind tools" ) add_custom_target(valgrind_memcheck COMMENT "Running Valgrind Memcheck" ) add_custom_target(valgrind_helgrind COMMENT "Running Valgrind Helgrind" ) add_custom_target(valgrind_cachegrind COMMENT "Running Valgrind Cachegrind" ) add_custom_target(valgrind_massif COMMENT "Running Valgrind Massif" ) # Function to automatically add valgrind tests for all executables function(enable_valgrind_for_target TARGET_NAME) add_valgrind_test(\${TARGET_NAME} MEMCHECK HELGRIND CACHEGRIND MASSIF) endfunction() else() message(WARNING "Valgrind not found. Memory analysis tools will not be available.") # Provide stub functions function(add_valgrind_test TARGET_NAME) # Do nothing endfunction() function(enable_valgrind_for_target TARGET_NAME) # Do nothing endfunction() endif() # Valgrind-specific compile flags function(add_valgrind_flags TARGET_NAME) target_compile_options(\${TARGET_NAME} PRIVATE -g3 # Maximum debug information -O0 # No optimization for accurate results -fno-omit-frame-pointer # Keep frame pointers for stack traces -fno-inline-functions # Disable inlining for clearer traces ) target_compile_definitions(\${TARGET_NAME} PRIVATE VALGRIND_BUILD=1 ) endfunction() # Integration with existing project if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND VALGRIND_EXECUTABLE) # Automatically enable valgrind for debug builds set(ENABLE_VALGRIND_BY_DEFAULT ON) else() set(ENABLE_VALGRIND_BY_DEFAULT OFF) endif() option(ENABLE_VALGRIND "Enable Valgrind memory analysis" \${ENABLE_VALGRIND_BY_DEFAULT})`; } static generateMemcheckSuppressions() { return `# Valgrind Memcheck Suppressions # Common false positives and known issues # Standard library suppressions { std_string_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:_ZNSs4_Rep9_S_createEmm* fun:_ZNSs4_Rep8_M_cloneERK* fun:_ZNSs7reserveEm } { std_locale_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm obj:*libstdc++* fun:_ZNSt6locale5facet* } # Thread-local storage suppressions { tls_false_positive Memcheck:Leak match-leak-kinds: reachable fun:calloc fun:_dl_allocate_tls fun:pthread_create@@GLIBC_* } # C++ global constructors/destructors { global_constructor_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:__static_initialization_and_destruction_* } { global_destructor_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:__cxa_atexit } # OpenSSL suppressions { openssl_init_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:CRYPTO_malloc fun:*SSL_library_init* } # glibc suppressions { glibc_dl_init Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_dl_new_object fun:_dl_map_object_from_fd } { glibc_getpwuid Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:nss_parse_service_list fun:__nss_database_lookup } # Boost suppressions { boost_thread_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:_ZN5boost6thread* } # JSON library suppressions (nlohmann/json) { json_allocator_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:_ZN8nlohmann* } # HTTP library suppressions (libcurl) { curl_global_init Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:curl_global_init } # Database driver suppressions (PostgreSQL) { postgresql_driver_init Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:PQconnectdb } # Custom application suppressions { app_singleton_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:*Singleton* } # Logging framework suppressions { spdlog_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:*spdlog* } # Testing framework suppressions { googletest_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:*testing* } # Benchmark framework suppressions { benchmark_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:*benchmark* } # Docker/containerization suppressions { container_runtime_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_dl_init obj:*/ld-*.so } # Suppressions for specific architectures { x86_64_syscall_param Memcheck:Param syscall(write) fun:write fun:_IO_file_write@@GLIBC_* } { arm64_specific_suppression Memcheck:Cond fun:__memcmp_sse4_1 fun:* } # Networking library suppressions { network_buffer_false_positive Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:*network* fun:*socket* } # Regex library suppressions { regex_compilation_leak Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:_Znwm fun:*regex* } # Crypto library suppressions { crypto_random_init Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:*random* fun:*crypto* }`; } static generateHelgrindSuppressions() { return `# Valgrind Helgrind Suppressions # Thread-related false positives # Standard library thread suppressions { std_thread_false_positive Helgrind:Race fun:_ZNSt6thread* } { std_mutex_false_positive Helgrind:Race fun:_ZNSt5mutex* } { std_condition_variable_false_positive Helgrind:Race fun:_ZNSt18condition_variable* } # C++ atomics suppressions { atomic_operations_false_positive Helgrind:Race fun:*atomic* } # Thread-local storage { tls_access_false_positive Helgrind:Race fun:*thread_local* } # glibc thread suppressions { glibc_thread_init Helgrind:Race fun:pthread_create@@GLIBC_* } { glibc_mutex_init Helgrind:Race fun:pthread_mutex_init } # Boost thread suppressions { boost_thread_library Helgrind:Race fun:_ZN5boost6thread* } { boost_mutex_library Helgrind:Race fun:_ZN5boost5mutex* } # OpenMP suppressions { openmp_false_positive Helgrind:Race fun:*omp* } # Intel TBB suppressions { tbb_false_positive Helgrind:Race fun:*tbb* } # Logging library thread safety { spdlog_thread_safety Helgrind:Race fun:*spdlog* } # JSON library thread safety { json_thread_safety Helgrind:Race fun:*nlohmann* } # HTTP client thread safety { http_client_thread_safety Helgrind:Race fun:*curl* } # Database connection pool { db_connection_pool_race Helgrind:Race fun:*connection* fun:*pool* } # Custom thread pool suppressions { custom_thread_pool_race Helgrind:Race fun:*ThreadPool* } # Signal handling suppressions { signal_handler_race Helgrind:Race fun:*signal* } # Memory allocator thread safety { allocator_thread_safety Helgrind:Race fun:malloc fun:free } # Static initialization race { static_init_race Helgrind:Race fun:__static_initialization_and_destruction_* } # Destructor race conditions { destructor_race Helgrind:Race fun:__cxa_finalize } # Exception handling races { exception_handling_race Helgrind:Race fun:__cxa_throw } # RTTI race conditions { rtti_race Helgrind:Race fun:__dynamic_cast } # Stream operations race { stream_operations_race Helgrind:Race fun:*iostream* } # Locale operations race { locale_operations_race Helgrind:Race fun:*locale* } # Time operations race { time_operations_race Helgrind:Race fun:*time* } # Random number generation race { random_generation_race Helgrind:Race fun:*random* } # Filesystem operations race { filesystem_operations_race Helgrind:Race fun:*filesystem* }`; } static generateValgrindScript(projectName, options) { return `#!/bin/bash # Comprehensive Valgrind Analysis Script for ${projectName} # Memory analysis, thread safety, and performance profiling set -euo pipefail # Configuration PROJECT_NAME="${projectName}" BUILD_DIR="build" EXECUTABLE_PATH="./\${BUILD_DIR}/\${PROJECT_NAME}" RESULTS_DIR="valgrind_results" TIMESTAMP="\\$(date +%Y%m%d_%H%M%S)" # Valgrind tools configuration ENABLE_MEMCHECK=${options.enableMemcheck} ENABLE_HELGRIND=${options.enableHelgrind} ENABLE_CACHEGRIND=${options.enableCachegrind} ENABLE_CALLGRIND=${options.enableCallgrind} ENABLE_MASSIF=${options.enableMassif} ENABLE_DRD=${options.enableDRD} # Colors for output RED='\\033[0;31m' GREEN='\\033[0;32m' BLUE='\\033[0;34m' YELLOW='\\033[1;33m' NC='\\033[0m' # No Color # Create results directory mkdir -p "\\${RESULTS_DIR}" echo -e "\\${BLUE}=== Valgrind Analysis Suite for \${PROJECT_NAME} ===\\${NC}" # Check if executable exists if [[ ! -f "\\${EXECUTABLE_PATH}" ]]; then echo -e "\\${RED}Error: Executable not found at \\${EXECUTABLE_PATH}\\${NC}" echo "Please build the project first with debug symbols:" echo "cmake -DCMAKE_BUILD_TYPE=Debug -B \\${BUILD_DIR}" echo "cmake --build \\${BUILD_DIR}" exit 1 fi # Check if valgrind is available if ! command -v valgrind &> /dev/null; then echo -e "\\${RED}Error: Valgrind not found. Please install valgrind.\\${NC}" exit 1 fi # Common valgrind flags COMMON_FLAGS=( --verbose --log-file="\\${RESULTS_DIR}/valgrind_\\${TIMESTAMP}.log" --time-stamp=yes --track-fds=yes --trace-children=yes ) # Function to run valgrind tool run_valgrind_tool() { local tool_name="\\$1" local tool_flags="\\$2" local output_file="\\$3" echo -e "\\${YELLOW}Running \\${tool_name}...\\${NC}" local start_time=\\$(date +%s) if valgrind \\${COMMON_FLAGS[]} \\${tool_flags} \\${EXECUTABLE_PATH} > "\\${output_file}.stdout" 2> "\\${output_file}.stderr"; then local end_time=\\$(date +%s) local duration=\\$((end_time - start_time)) echo -e "\\${GREEN}\\${tool_name} completed successfully in \\${duration}s\\${NC}" echo -e "Results saved to \\${output_file}.*" return 0 else echo -e "\\${RED}\\${tool_name} detected issues. Check \\${output_file}.stderr\\${NC}" return 1 fi } # Memcheck - Memory error detection if [[ "\\${ENABLE_MEMCHECK}" == "true" ]]; then MEMCHECK_FLAGS=( --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --show-reachable=yes --error-exitcode=1 --gen-suppressions=all --suppressions=valgrind/memcheck.supp --xml=yes --xml-file="\\${RESULTS_DIR}/memcheck_\\${TIMESTAMP}.xml" ) run_valgrind_tool "Memcheck" "\\${MEMCHECK_FLAGS[ * ]}" "\\${RESULTS_DIR}/memcheck_\\${TIMESTAMP}" MEMCHECK_EXIT_CODE=\\$? fi # Helgrind - Thread error detection if [[ "\\${ENABLE_HELGRIND}" == "true" ]]; then HELGRIND_FLAGS=( --tool=helgrind --history-level=full --conflict-cache-size=1000000 --suppressions=valgrind/helgrind.supp --xml=yes --xml-file="\\${RESULTS_DIR}/helgrind_\\${TIMESTAMP}.xml" ) run_valgrind_tool "Helgrind" "\\${HELGRIND_FLAGS[ * ]}" "\\${RESULTS_DIR}/helgrind_\\${TIMESTAMP}" HELGRIND_EXIT_CODE=\\$? fi # Cachegrind - Cache profiling if [[ "\\${ENABLE_CACHEGRIND}" == "true" ]]; then CACHEGRIND_FLAGS=( --tool=cachegrind --cache-sim=yes --branch-sim=yes --cachegrind-out-file="\\${RESULTS_DIR}/cachegrind_\\${TIMESTAMP}.out" ) run_valgrind_tool "Cachegrind" "\\${CACHEGRIND_FLAGS[ * ]}" "\\${RESULTS_DIR}/cachegrind_\\${TIMESTAMP}" # Generate cachegrind annotation if command -v cg_annotate &> /dev/null; then echo -e "\\${YELLOW}Generating Cachegrind annotation...\\${NC}" cg_annotate "\\${RESULTS_DIR}/cachegrind_\\${TIMESTAMP}.out" > "\\${RESULTS_DIR}/cachegrind_\\${TIMESTAMP}_annotation.txt" fi fi # Callgrind - Call profiling if [[ "\\${ENABLE_CALLGRIND}" == "true" ]]; then CALLGRIND_FLAGS=( --tool=callgrind --dump-instr=yes --collect-jumps=yes --collect-systime=yes --callgrind-out-file="\\${RESULTS_DIR}/callgrind_\\${TIMESTAMP}.out" ) run_valgrind_tool "Callgrind" "\\${CALLGRIND_FLAGS[ * ]}" "\\${RESULTS_DIR}/callgrind_\\${TIMESTAMP}" # Generate callgrind annotation if command -v callgrind_annotate &> /dev/null; then echo -e "\\${YELLOW}Generating Callgrind annotation...\\${NC}" callgrind_annotate "\\${RESULTS_DIR}/callgrind_\\${TIMESTAMP}.out" > "\\${RESULTS_DIR}/callgrind_\\${TIMESTAMP}_annotation.txt" fi fi # Massif - Heap profiling if [[ "\\${ENABLE_MASSIF}" == "true" ]]; then MASSIF_FLAGS=( --tool=massif --heap=yes --stacks=yes --depth=30 --threshold=0.1 --peak-inaccuracy=0.1 --time-unit=ms --massif-out-file="\\${RESULTS_DIR}/massif_\\${TIMESTAMP}.out" ) run_valgrind_tool "Massif" "\\${MASSIF_FLAGS[ * ]}" "\\${RESULTS_DIR}/massif_\\${TIMESTAMP}" # Generate massif visualization if command -v ms_print &> /dev/null; then echo -e "\\${YELLOW}Generating Massif visualization...\\${NC}" ms_print "\\${RESULTS_DIR}/massif_\\${TIMESTAMP}.out" > "\\${RESULTS_DIR}/massif_\\${TIMESTAMP}_graph.txt" fi fi # DRD - Data race detection if [[ "\\${ENABLE_DRD}" == "true" ]]; then DRD_FLAGS=( --tool=drd --check-stack-var=yes --exclusive-threshold=10 --segment-merging=yes --shared-threshold=10 --xml=yes --xml-file="\\${RESULTS_DIR}/drd_\\${TIMESTAMP}.xml" ) run_valgrind_tool "DRD" "\\${DRD_FLAGS[ * ]}" "\\${RESULTS_DIR}/drd_\\${TIMESTAMP}" DRD_EXIT_CODE=\\$? fi # Generate comprehensive report echo -e "\\${BLUE}=== Generating Analysis Report ===\\${NC}" if command -v python3 &> /dev/null; then python3 scripts/valgrind_analysis.py \\ --results-dir "\\${RESULTS_DIR}" \\ --timestamp "\\${TIMESTAMP}" \\ --project-name "\\${PROJECT_NAME}" \\ --output "\\${RESULTS_DIR}/analysis_report_\\${TIMESTAMP}.html" echo -e "\\${GREEN}Comprehensive report generated: \\${RESULTS_DIR}/analysis_report_\\${TIMESTAMP}.html\\${NC}" fi # Summary echo -e "\\${BLUE}=== Valgrind Analysis Summary ===\\${NC}" echo "Project: \\${PROJECT_NAME}" echo "Timestamp: \\${TIMESTAMP}" echo "Results directory: \\${RESULTS_DIR}" echo "" # Exit status summary OVERALL_EXIT_CODE=0 if [[ "\\${ENABLE_MEMCHECK}" == "true" ]]; then if [[ \\${MEMCHECK_EXIT_CODE; -0; } } exports.CppValgrindGenerator = CppValgrindGenerator; -eq; 0; ; then; echo - e; "\\${GREEN}✓ Memcheck: No memory errors detected\\${NC}"; echo - e; "\\${RED}✗ Memcheck: Memory errors detected\\${NC}"; OVERALL_EXIT_CODE = 1; fi; fi; if ([["\\${ENABLE_HELGRIND}" == "true"]]) ; then; if ([[$, { HELGRIND_EXIT_CODE: -0 } - eq, 0]]) ; then; echo - e; "\\${GREEN}✓ Helgrind: No thread errors detected\\${NC}"; echo - e; "\\${RED}✗ Helgrind: Thread errors detected\\${NC}"; OVERALL_EXIT_CODE = 1; fi; fi; if ([["\\${ENABLE_DRD}" == "true"]]) ; then; if ([[$, { DRD_EXIT_CODE: -0 } - eq, 0]]) ; then; echo - e; "\\${GREEN}✓ DRD: No data races detected\\${NC}"; echo - e; "\\${RED}✗ DRD: Data races detected\\${NC}"; OVERALL_EXIT_CODE = 1; fi; fi; echo; ""; echo; "For detailed analysis, check individual result files in \\${RESULTS_DIR}/"; if ([[$, { OVERALL_EXIT_CODE } - eq, 0]]) ; then; echo - e; "\\${GREEN}All Valgrind tools passed successfully!\\${NC}"; echo - e; "\\${RED}Some Valgrind tools detected issues. Please review the results.\\${NC}"; fi; exit; $; { OVERALL_EXIT_CODE; } `; } private static generateValgrindAnalysis(): string { return `; !/usr/bin / env; python3; ""; "; Valgrind; Analysis; Tool; Processes; Valgrind; output; and; generates; comprehensive; reports; ""; "; var os = ; var argparse = ; as; ET; from; module_1.default; const module_1 = __importDefault(require()); const module_2 = __importDefault(require()); var re = ; class ValgrindAnalyzer { } def; __init__(self, results_dir, str, timestamp, str, project_name, str); self.results_dir = results_dir; self.timestamp = timestamp; self.project_name = project_name; self.analysis_results = {}; def; parse_memcheck_xml(self, xml_file, str) - > module_2.default[str, Any]; ""; "Parse Memcheck XML output."; ""; try { } finally { } tree = ET.parse(xml_file); root = tree.getroot(); errors = []; for (error in root.findall('.//error')) : error_data = { 'kind': error.find('kind').text, if: error.find('kind'), is, not, None, else: '', 'what': error.find('what').text, if: error.find('what'), is, not, None, else: '', 'stack': [] }; #; Parse; stack; trace; stack = error.find('stack'); if (stack) is; not; None: for (frame in stack.findall('frame')) : frame_data = {}; if (frame.find('fn')) is; not; None: frame_data['function'] = frame.find('fn').text; if (frame.find('file')) is; not; None: frame_data['file'] = frame.find('file').text; if (frame.find('line')) is; not; None: frame_data['line'] = frame.find('line').text; error_data['stack'].append(frame_data); errors.append(error_data); return { 'tool': 'memcheck', 'errors': errors, 'error_count': len(errors) }; except; Exception; print(f, "Error parsing Memcheck XML: {e}"); return { 'tool': 'memcheck', 'errors': [], 'error_count': 0 }; def; parse_helgrind_xml(self, xml_file, str) - > module_2.default[str, Any]; ""; "Parse Helgrind XML output."; ""; try { } finally { } tree = ET.parse(xml_file); root = tree.getroot(); errors = []; for (error in root.findall('.//error')) : error_data = { 'kind': error.find('kind').text, if: error.find('kind'), is, not, None, else: '', 'what': error.find('what').text, if: error.find('what'), is, not, None, else: '', 'stack': [] }; #; Parse; stack; trace; stack = error.find('stack'); if (stack) is; not; None: for (frame in stack.findall('frame')) : frame_data = {}; if (frame.find('fn')) is; not; None: frame_data['function'] = frame.find('fn').text; if (frame.find('file')) is; not; None: frame_data['file'] = frame.find('file').text; if (frame.find('line')) is; not; None: frame_data['line'] = frame.find('line').text; error_data['stack'].append(frame_data); errors.append(error_data); return { 'tool': 'helgrind', 'errors': errors, 'error_count': len(errors) }; except; Exception; print(f, "Error parsing Helgrind XML: {e}"); return { 'tool': 'helgrind', 'errors': [], 'error_count': 0 }; def; parse_cachegrind_output(self, output_file, str) - > module_2.default[str, Any]; ""; "Parse Cachegrind output."; ""; try { } finally { } with (open(output_file, 'r')) : content = f.read(); #; Extract; summary; statistics; stats = {}; for (line in content.split('\\n')) : if ('I refs:' in line) : stats['instruction_refs'] = self.extract_number(line); elif; 'I1 misses:' in line; stats['l1_instruction_misses'] = self.extract_number(line); elif; 'LLi misses:' in line; stats['ll_instruction_misses'] = self.extract_number(line); elif; 'D refs:' in line; stats['data_refs'] = self.extract_number(line); elif; 'D1 misses:' in line; stats['l1_data_misses'] = self.extract_number(line); elif; 'LLd misses:' in line; stats['ll_data_misses'] = self.extract_number(line); return { 'tool': 'cachegrind', 'stats': stats }; except; Exception; print(f, "Error parsing Cachegrind output: {e}"); return { 'tool': 'cachegrind', 'stats': {} }; def; parse_massif_output(self, output_file, str) - > module_2.default[str, Any]; ""; "Parse Massif output."; ""; try { } finally { } with (open(output_file, 'r')) : content = f.read(); #; Extract; memory; usage; statistics; stats = {}; peak_usage = 0; snapshots = []; for (line in content.split('\\n')) : if (line.startswith('mem_heap_B=')) : heap_usage = int(line.split('=')[1]); peak_usage = max(peak_usage, heap_usage); elif; line.startswith('snapshot='); snapshot_data = self.parse_massif_snapshot(line); if (snapshot_data) : snapshots.append(snapshot_data); stats['peak_heap_usage'] = peak_usage; stats['snapshots'] = snapshots; return { 'tool': 'massif', 'stats': stats }; except; Exception; print(f, "Error parsing Massif output: {e}"); return { 'tool': 'massif', 'stats': {} }; def; extract_number(self, line, str) - > int; ""; "Extract number from line with commas."; ""; match = re.search(r, '([0-9,]+)', line); if (match) : return int(match.group(1).replace(',', '')); return 0; def; parse_massif_snapshot(self, line, str) - > Optional[module_2.default[str, Any]]; ""; "Parse Massif snapshot line."; ""; try { } finally { } parts = line.split('='); if (len(parts) >= 2) : return { 'snapshot': int(parts[1].split('#')[0]), 'time': parts[2], if: len(parts) > 2, else: 0 }; except: pass; return None; def; analyze_results(self); ""; "Analyze all available Valgrind results."; ""; #; Check; for (Memcheck; results; memcheck_xml = os.path.join(self.results_dir, f, 'memcheck_{self.timestamp}.xml')) if (os.path.exists(memcheck_xml)) : self.analysis_results['memcheck'] = self.parse_memcheck_xml(memcheck_xml); #; Check; for (Helgrind; results; helgrind_xml = os.path.join(self.results_dir, f, 'helgrind_{self.timestamp}.xml')) if (os.path.exists(helgrind_xml)) : self.analysis_results['helgrind'] = self.parse_helgrind_xml(helgrind_xml); #; Check; for (Cachegrind; results; cachegrind_out = os.path.join(self.results_dir, f, 'cachegrind_{self.timestamp}.out')) if (os.path.exists(cachegrind_out)) : self.analysis_results['cachegrind'] = self.parse_cachegrind_output(cachegrind_out); #; Check; for (Massif; results; massif_out = os.path.join(self.results_dir, f, 'massif_{self.timestamp}.out')) if (os.path.exists(massif_out)) : self.analysis_results['massif'] = self.parse_massif_output(massif_out); def; generate_html_report(self, output_file, str); ""; "Generate comprehensive HTML report."; ""; html_content = f; ""; " < !DOCTYPE; html > Valgrind; Analysis; Report - { self, : .project_name } < (/title>); body; { { font - family; Arial, sans - serif; margin: 20; px; } } header; { { background - color; #f0f0f0; padding: 20; px; border - radius; 5; px; } } section; { { margin: 20; px; 0; padding: 15; px; border: 1; px; solid; #ddd; border - radius; 5; px; } } error; { { background - color; #ffebee; border - left; 4; px; solid; #f44336; } } warning; { { background - color; #fff3e0; border - left; 4; px; solid; #ff9800; } } success; { { background - color; #e8f5e8; border - left; 4; px; solid; #; 4; caf50; } } info; { { background - color; #e3f2fd; border - left; 4; px; solid; #; 2196; f3; } } stack - trace; { { background - color; #f5f5f5; padding: 10; px; font - family; monospace; } } table; { { border - collapse; collapse; width: 100 % ; } } th, td; { { border: 1; px; solid; #ddd; padding: 8; px; text - align; left; } } th; { { background - color; #f2f2f2; } } metric; { { font - size; 1.2e; m; font - weight; bold; } } /style> < /head> < body > class { }; "header" > Valgrind; Analysis; Report < /h1> < p > Project; /strong> {self.project_name}</p > Timestamp; /strong> {self.timestamp}</p > Generated; /strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p > /div>; ""; "; #; Executive; Summary; html_content += self.generate_executive_summary(); #; Detailed; results; for (each; tool; ) for (tool, results in self.analysis_results.items()) : html_content += self.generate_tool_section(tool, results); #; Recommendations; html_content += self.generate_recommendations(); html_content += ""; " < /body> < /html>; ""; "; with (open(output_file, 'w')) : f.write(html_content); def; generate_executive_summary(self) - > str; ""; "Generate executive summary section."; ""; total_errors = 0; tools_run = []; for (tool, results in self.analysis_results.items()) : tools_run.append(tool); if ('error_count' in results) : total_errors += results['error_count']; status_class = 'success'; if (total_errors == 0) ; else 'error'; return f; ""; " < div; class { } "section {status_class}" > Executive; Summary < /h2> < p > class { }; "metric" > Total; Errors: { total_errors; } /span></p > Tools; Run: /strong> {', '.join(tools_run)}</p > Status; /strong> {'✓ Clean' if total_errors == 0 else '✗ Issues Found'}</p > /div>; ""; "; def; generate_tool_section(self, tool, str, results, module_2.default[str, Any]) - > str; ""; "Generate section for specific tool results."; ""; if (tool == 'memcheck') : return self.generate_memcheck_section(results); elif; tool == 'helgrind'; return self.generate_helgrind_section(results); elif; tool == 'cachegrind'; return self.generate_cachegrind_section(results); elif; tool == 'massif'; return self.generate_massif_section(results); return f; '<div class="section info"><h3>{tool.title()}</h3><p>Results available</p></div>'; def; generate_memcheck_section(self, results, module_2.default[str, Any]) - > str; ""; "Generate Memcheck results section."; ""; error_count = results.get('error_count', 0); status_class = 'success'; if (error_count == 0) ; else 'error'; content = f; ""; " < div; class { } "section {status_class}" > Memcheck; Results < /h2> < p > class { }; "metric" > Memory; Errors: { error_count; } /span></p > ""; "; if (error_count > 0) : content += "<h3>Error Details</h3>"; for (i, error in enumerate(results.get('errors', [])[], 10)) : #; Show; first; 10; errors; content += f; ""; " < div; class { } "error" > Error; { i + 1; } { error.get('kind', 'Unknown'); } /h4> < p > { error, : .get('what', 'No description') } < /p>; ""; "; if (error.get('stack')) : content += '<div class="stack-trace">'; for (frame in error['stack'][]) : 5; #; Show; first; 5; frames; func = frame.get('function', 'Unknown'); file_line = f; "{frame.get('file', 'Unknown')}:{frame.get('line', '?')}"; content += f; " {func} ({file_line})<br>"; content += '</div>'; content += '</div>'; content += '</div>'; return content; def; generate_helgrind_section(self, results, module_2.default[str, Any]) - > str; ""; "Generate Helgrind results section."; ""; error_count = results.get('error_count', 0); status_class = 'success'; if (error_count == 0) ; else 'error'; return f; ""; " < div; class { } "section {status_class}" > Helgrind; Results < /h2> < p > class { }; "metric" > Thread; Errors: { error_count; } /span></p > { '<p>No thread safety issues detected.</p>': , if: error_count == 0, else: '<p>Thread safety issues detected. Check detailed logs.</p>' } < /div>; ""; "; def; generate_cachegrind_section(self, results, module_2.default[str, Any]) - > str; ""; "Generate Cachegrind results section."; ""; stats = results.get('stats', {}); content = ""; " < div; class { } "section info" > Cachegrind; Results < /h2> < table > Metric < /th><th>Value</th > /tr>; ""; "; for (metric, value in stats.items()) : formatted_value = f; "{value:,}"; if (isinstance(value, int)) ; else str(value); content += f; "<tr><td>{metric.replace('_', ' ').title()}</td><td>{formatted_value}</td></tr>"; content += ""; " < /table> < /div>; ""; "; return content; def; generate_massif_section(self, results, module_2.default[str, Any]) - > str; ""; "Generate Massif results section."; ""; stats = results.get('stats', {}); peak_usage = stats.get('peak_heap_usage', 0); return f; ""; " < div; class { } "section info" > Massif; Results < /h2> < p > class { }; "metric" > Peak; Heap; Usage: { peak_usage: , ; } bytes < /span></p > class { }; "metric" > Peak; Heap; Usage: { peak_usage / 1024 / 1024; .2; f; } MB < /span></p > Snapshots; { len(stats.get('snapshots', [])); } /p> < /div>; ""; "; def; generate_recommendations(self) - > str; ""; "Generate recommendations section."; ""; recommendations = []; #; Check; for (memory; errors; ) if ('memcheck' in self.analysis_results) : error_count = self.analysis_results['memcheck'].get('error_count', 0); if (error_count > 0) : recommendations.append("Fix memory leaks and invalid memory accesses detected by Memcheck"); #; Check; for (thread; errors; ) if ('helgrind' in self.analysis_results) : error_count = self.analysis_results['helgrind'].get('error_count', 0); if (error_count > 0) : recommendations.append("Address thread safety issues detected by Helgrind"); #; Performance; recommendations; if ('cachegrind' in self.analysis_results) : recommendations.append("Review cache usage patterns for performance optimization"); if ('massif' in self.analysis_results) : recommendations.append("Monitor heap usage patterns for memory optimization"); if (not) recommendations: recommendations.append("No issues detected. Continue with regular monitoring."); content = ""; " < div; class { } "section warning" > Recommendations < (/h2>); ""; "; for (rec in recommendations) : content += f; "<li>{rec}</li>"; content += ""; " < /ul> < /div>; ""; "; return content; def; main(); parser = argparse.ArgumentParser(description = 'Analyze Valgrind results'); parser.add_argument('--results-dir', required = True, help = 'Directory containing Valgrind results'); parser.add_argument('--timestamp', required = True, help = 'Timestamp for result files'); parser.add_argument('--project-name', required = True, help = 'Project name'); parser.add_argument('--output', required = True, help = 'Output HTML file'); args = parser.parse_args(); analyzer = ValgrindAnalyzer(args.results_dir, args.timestamp, args.project_name); analyzer.analyze_results(); analyzer.generate_html_report(args.output); print(f, "Analysis complete. Report saved to {args.output}"); if (__name__ == '__main__') : main() `; } private static generateValgrindReadme(projectName: string): string { return `; #; Valgrind; Memory; Analysis; for ($; { projectName }; This) directory; contains; Valgrind; configuration; and; tools; for (comprehensive; memory; analysis) and; debugging. ; #; #; Overview; Valgrind; is; a; powerful; suite; of; tools; for (debugging; and; profiling) programs: - ** Memcheck ** ; Memory; error; detection(leaks, invalid, accesses, uninitialized, memory) - ** Helgrind ** ; Thread; error; detection(race, conditions, deadlocks) - ** Cachegrind ** ; Cache; profiling; and; performance; analysis - ** Callgrind ** ; Call; profiling; and; performance; analysis - ** Massif ** ; Heap; profiling; and; memory; usage; analysis - ** DRD ** ; Alternative; thread; error; detection; #; #; Quick; Start; #; #; #; Building; for (Valgrind; ; ) ; `\`\`bash # Build with debug symbols and no optimization cmake -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_VALGRIND=ON cmake --build build \`\`\` ### Running Analysis \`\`\`bash # Run comprehensive analysis ./scripts/run_valgrind.sh # Run specific tool valgrind --tool=memcheck --leak-check=full ./build/${projectName} # Run with CMake/CTest ctest -R valgrind \`\`\` ## Tools Overview ### Memcheck - Memory Error Detection **Purpose**: Detect memory leaks, buffer overflows, use of uninitialized memory **Common Issues Detected**: - Memory leaks (heap, stack) - Invalid memory accesses - Use of uninitialized memory - Double free errors - Mismatched malloc/free and new/delete **Usage**: \`\`\`bash valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./build/${projectName} \`\`\` ### Helgrind - Thread Error Detection **Purpose**: Detect race conditions and threading issues **Common Issues Detected**: - Data races - Lock ordering problems - Misuse of POSIX pthreads API - Inconsistent lock acquisition **Usage**: \`\`\`bash valgrind --tool=helgrind ./build/${projectName} \`\`\` ### Cachegrind - Cache Profiling **Purpose**: Analyze cache usage and performance **Metrics Provided**: - L1/L2/L3 cache misses - Branch misprediction rates - Instruction execution counts **Usage**: \`\`\`bash valgrind --tool=cachegrind ./build/${projectName} # View results cg_annotate cachegrind.out.{pid} \`\`\` ### Massif - Heap Profiling **Purpose**: Analyze heap memory usage over time **Features**: - Heap usage snapshots - Memory allocation patterns - Peak memory usage identification **Usage**: \`\`\`bash valgrind --tool=massif ./build/${projectName} # View results ms_print massif.out.{pid} \`\`\` ## Configuration Files ### Suppression Files - \`memcheck.supp\`: Suppresses known false positives in Memcheck - \`helgrind.supp\`: Suppresses known false positives in Helgrind ### Tool Configuration - \`configs/memcheck.conf\`: Memcheck-specific settings - \`configs/helgrind.conf\`: Helgrind-specific settings - \`configs/cachegrind.conf\`: Cachegrind-specific settings - \`configs/massif.conf\`: Massif-specific settings ## Integration with Build System ### CMake Integration The project includes CMake functions for easy Valgrind integration: \`\`\`cmake # Add Valgrind tests for an executable add_valgrind_test(my_executable MEMCHECK HELGRIND) # Add Valgrind flags to a target add_valgrind_flags(my_target) # Enable Valgrind for all targets enable_valgrind_for_target(my_target) \`\`\` ### CTest Integration Run Valgrind tests through CTest: \`\`\`bash # Run all Valgrind tests ctest -R valgrind # Run specific tool tests ctest -R valgrind_memcheck ctest -R valgrind_helgrind \`\`\` ## Continuous Integration ### GitHub Actions The project includes GitHub Actions workflow for automated Valgrind analysis: - Runs on pull requests and main branch - Detects memory leaks and thread errors - Generates detailed reports - Fails builds on critical issues ### Docker Support Use the provided Docker image for consistent analysis: \`\`\`bash # Build Valgrind Docker image docker build -f valgrind/docker/Dockerfile.valgrind -t ${projectName}-valgrind . # Run analysis in container docker run --rm -v \$(pwd):/workspace ${projectName}-valgrind \`\`\` ## Analysis and Reporting ### Automated Analysis The \`valgrind_analysis.py\` script provides: - XML report parsing - HTML report generation - Error categorization and prioritization - Performance metrics analysis ### Memory Report Generation \`\`\`bash # Generate comprehensive memory report python3 scripts/memory_report.py --results-dir valgrind_results \`\`\` ## Best Practices ### Writing Valgrind-Friendly Code 1. **Use RAII**: Ensure automatic cleanup of resources 2. **Initialize variables**: Avoid uninitialized memory access 3. **Proper synchronization**: Use mutexes and locks correctly 4. **Avoid raw pointers**: Use smart pointers when possible ### Debugging with Valgrind 1. **Build with debug symbols**: Use \`-g\` flag 2. **Disable optimization**: Use \`-O0\` for accurate results 3. **Use suppressions**: Filter out known false positives 4. **Start with Memcheck**: Address memory issues first ### Performance Considerations - Valgrind slows down execution 10-50x - Use suppressions to reduce noise - Run on representative workloads - Focus on critical code paths ## Troubleshooting ### Common Issues 1. **False positives**: Add suppressions for known issues 2. **Slow execution**: Use minimal test cases 3. **Missing debug info**: Ensure debug symbols are included 4. **System library issues**: Use system-specific suppressions ### Debugging Tips \`\`\`bash # Get more detailed output valgrind --verbose --track-origins=yes # Generate suppressions automatically valgrind --gen-suppressions=all # Increase verbosity for debugging valgrind --verbose --trace-children=yes \`\`\` ## Integration with IDEs ### Visual Studio Code Add launch configuration for Valgrind debugging: \`\`\`json { "name": "Valgrind Debug", "type": "cppdbg", "request": "launch", "program": "valgrind", "args": ["--tool=memcheck", "--leak-check=full", "./build/${projectName}"], "stopAtEntry": false, "cwd": "\${workspaceFolder}", "environment": [], "externalConsole": false } \`\`\` ### CLion Configure Valgrind as external tool: 1. Go to File → Settings → Tools → External Tools 2. Add new tool with Valgrind configuration 3. Use custom run configuration ## Resources - [Valgrind Documentation](https://valgrind.org/docs/) - [Memcheck Manual](https://valgrind.org/docs/manual/mc-manual.html) - [Helgrind Manual](https://valgrind.org/docs/manual/hg-manual.html) - [Performance Analysis Guide](https://valgrind.org/docs/manual/manual-core.html)`; generateValgrindCI(projectName, string); string; { return `name: Valgrind Memory Analysis on: push: branches: [ main, develop ] pull_request: branches: [ main ] schedule: # Run nightly analysis at 3 AM UTC - cron: '0 3 * * *' env: BUILD_TYPE: Debug jobs: valgrind-analysis: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \\ valgrind \\ cmake \\ ninja-build \\ gcc-11 \\ g++-11 \\ python3-pip \\ python3-lxml pip3 install matplotlib seaborn pandas - name: Configure CMake run: | cmake -B build \\ -DCMAKE_BUILD_TYPE=\\${{ env, : .BUILD_TYPE }} \\ -DCMAKE_CXX_COMPILER=g++-11 \\ -DCMAKE_C_COMPILER=gcc-11 \\ -DENABLE_VALGRIND=ON \\ -GNinja - name: Build run: cmake --build build --config \\${{ env, : .BUILD_TYPE }} - name: Run Valgrind Memcheck run: | mkdir -p valgrind_results # Run Memcheck valgrind \\ --tool=memcheck \\ --leak-check=full \\ --show-leak-kinds=all \\ --track-origins=yes \\ --verbose \\ --xml=yes \\ --xml-file=valgrind_results/memcheck.xml \\ --error-exitcode=1 \\ --suppressions=valgrind/memcheck.supp \\ ./build/${projectName} \\ 2>&1 | tee valgrind_results/memcheck.log continue-on-error: true id: memcheck - name: Run Valgrind Helgrind run: | # Run Helgrind (thread error detection) valgrind \\ --tool=helgrind \\ --verbose \\ --xml=yes \\ --xml-file=valgrind_results/helgrind.xml \\ --error-exitcode=1 \\ --suppressions=valgrind/helgrind.supp \\ ./build/${projectName} \\ 2>&1 | tee valgrind_results/helgrind.log continue-on-error: true id: helgrind - name: Run Valgrind Cachegrind run: | # Run Cachegrind (cache profiling) valgrind \\ --tool=cachegrind \\ --verbose \\ --cachegrind-out-file=valgrind_results/cachegrind.out \\ ./build/${projectName} \\ 2>&1 | tee valgrind_results/cachegrind.log # Generate annotation if available if command -v cg_annotate &> /dev/null; then cg_annotate valgrind_results/cachegrind.out > valgrind_results/cachegrind_annotation.txt fi continue-on-error: true - name: Run Valgrind Massif run: | # Run Massif (heap profiling) valgrind \\ --tool=massif \\ --verbose \\ --massif-out-file=valgrind_results/massif.out \\ --heap=yes \\ --stacks=yes \\ --time-unit=ms \\ ./build/${projectName} \\ 2>&1 | tee valgrind_results/massif.log # Generate visualization if available if command -v ms_print &> /dev/null; then ms_print valgrind_results/massif.out > valgrind_results/massif_graph.txt fi continue-on-error: true - name: Generate Analysis Report run: | # Generate comprehensive analysis report python3 scripts/valgrind_analysis.py \\ --results-dir valgrind_results \\ --timestamp \\$(date +%Y%m%d_%H%M%S) \\