diff --git a/.arcconfig b/.arcconfig deleted file mode 100644 index ef0e7246..00000000 --- a/.arcconfig +++ /dev/null @@ -1,3 +0,0 @@ -{ - "phabricator.uri" : "https://phabricator.kde.org/project/profile/74/" -} diff --git a/.gitignore b/.gitignore index d89b685c..9f87cc0b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,12 @@ perf.data.* callgrind.out.* .*kate-swp +# IDEs/clangd +.clangd +.cache +compile_commands.json +.idea + # from kdiff3 *.BACKUP.* *.BASE.* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..a4a7cdd6 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,2 @@ +include: + - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml diff --git a/.kde-ci.yml b/.kde-ci.yml new file mode 100644 index 00000000..e3306b66 --- /dev/null +++ b/.kde-ci.yml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: None +# SPDX-License-Identifier: CC0-1.0 + +Dependencies: +- 'on': ['@all'] + 'require': + 'frameworks/extra-cmake-modules': '@stable' + 'frameworks/kcoreaddons': '@stable' + 'frameworks/ki18n': '@stable' + 'frameworks/kitemmodels': '@stable' + 'frameworks/kconfigwidgets': '@stable' + 'frameworks/kio': '@stable' + 'frameworks/kiconthemes': '@stable' + 'frameworks/threadweaver': '@stable' + 'graphics/kdiagram': '@stable' diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 00000000..2a0871f2 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,17 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: heaptrack +Upstream-Contact: Milian Wolff +Source: https://invent.kde.org/sdk/heaptrack + +Files: 3rdparty/robin-map/* +Copyright: 2017 Thibaut Goetghebuer-Planchon +License: MIT + +Files: 3rdparty/boost-zstd/* +Copyright: Boost developers +License: BSL-1.0 + +Files: 3rdparty/doctest.h +Copyright: Copyright (c) 2016-2023 Viktor Kirilov +License: MIT + diff --git a/.travis.yml b/.travis.yml index 95dd9c90..b005b990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,66 +1,17 @@ language: cpp compiler: gcc -sudo: require -dist: trusty +os: linux +dist: xenial -before_install: - - sudo add-apt-repository ppa:beineri/opt-qt-5.10.1-trusty -y - - sudo apt-get update -qq +services: + - docker install: - - sudo apt-get -y install qt510base qt510svg qt510x11extras libdwarf-dev libboost-iostreams-dev libboost-program-options-dev - - source /opt/qt*/bin/qt*-env.sh - - # ecm - - git clone git://anongit.kde.org/extra-cmake-modules - - cd extra-cmake-modules && mkdir build && cd build && cmake .. && make -j$(nproc) && sudo make install && cd ../.. - - # zstd - - git clone https://github.com/facebook/zstd.git - - cd zstd && make -j$(nproc) && sudo make install && cd .. - - # Precompiled KF5 - - wget -nv -c "https://github.com/chigraph/precompiled-kf5-linux/releases/download/precompiled/kf5-gcc6-linux64-release.tar.xz" - - tar xf kf5-gcc6-linux64-release.tar.xz - - sudo cp -Rf root/kf5-release/* /opt/qt*/ - - # kdiagram - - git clone git://anongit.kde.org/kdiagram - - cd kdiagram && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/qt510 -DBUILD_KGantt=OFF -DBUILD_TESTING=OFF .. && make -j$(nproc) && sudo make install && cd ../../ - - # Precompiled version of libunwind in newer version (1.)2 - - wget -nv -c "https://swanson.kdab.com/owncloud/index.php/s/ZETvRRZ7J5Nllo5/download" -O libunwind.tar.bz2 - - tar xf libunwind.tar.bz2 - - sudo cp -Rf libunwind-*/usr/* /usr/ - - # Get AppImage tools - - wget -nv -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" - - chmod a+x linuxdeployqt*.AppImage - - sudo mv linuxdeployqt*.AppImage /usr/bin/linuxdeployqt - - wget -nv -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" - - chmod a+x appimagetool-*.AppImage - - sudo mv appimagetool-*.AppImage /usr/bin/appimagetool - wget -nv -c https://github.com/probonopd/uploadtool/raw/master/upload.sh - chmod a+x upload.sh - sudo mv upload.sh /usr/bin/github-upload script: - set -e # Exit immediately if anything fails - - mkdir build - - cd build - - cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DAPPIMAGE_BUILD=ON - - make -j$(nproc) - - make DESTDIR=appdir install - - unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH - - export LD_LIBRARY_PATH=/opt/qt510/lib/x86_64-linux-gnu # make sure this path is known so all Qt/KF5 libs are found - - linuxdeployqt ./appdir/usr/share/applications/org.kde.heaptrack.desktop -executable=./appdir/usr/lib/heaptrack/libexec/heaptrack_interpret -executable=./appdir/usr/lib/heaptrack/libheaptrack_preload.so -executable=./appdir/usr/lib/heaptrack/libheaptrack_inject.so -bundle-non-qt-libs - - # Ensure we prefer the bundled libs also when calling dlopen, cf.: https://github.com/KDAB/hotspot/issues/89 - - mv ./appdir/usr/bin/heaptrack_gui{,_bin} - - echo -e '#!/bin/bash\nf="$(readlink -f "${0}")"\nd="$(dirname "$f")"\nLD_LIBRARY_PATH="$d/../lib:$LD_LIBRARY_PATH" "$d/heaptrack_gui_bin" "$@"' > ./appdir/usr/bin/heaptrack_gui - - chmod +x ./appdir/usr/bin/heaptrack_gui - - # include breeze icons - - cp -a /opt/qt*/share/icons/breeze ./appdir/usr/share/icons/ - - # include zstd binary - - cp $(which zstd) ./appdir/usr/bin/zstd - - # use the shell script as AppRun entry point - - rm ./appdir/AppRun - - ln -sr ./appdir/usr/bin/heaptrack ./appdir/AppRun - - # Actually create the final image - - appimagetool ./appdir/ - - # upload the appimage to GitHub - - mv Heaptrack-*.AppImage heaptrack-git.$(git rev-parse --short HEAD)-x86_64.AppImage - - github-upload ./heaptrack-git.*-x86_64.AppImage + - ./tools/build_appimage_in_docker.sh + - github-upload ./heaptrack-*.AppImage diff --git a/3rdparty/.clang-format b/3rdparty/.clang-format new file mode 100644 index 00000000..9d159247 --- /dev/null +++ b/3rdparty/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 4ac34589..a2c8e69b 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -2,10 +2,22 @@ if (ECM_FOUND) include(ECMEnableSanitizers) endif() -if (HEAPTRACK_BUILD_BACKTRACE) - add_subdirectory(libbacktrace) -endif() +# Mark the specified target's include directories as INTERFACE_SYSTEM_INCLUDE_DIRECTORIES +function(mark_as_system_target target) + # see also: https://gitlab.kitware.com/cmake/cmake/-/issues/21211 + get_property( + include_dirs + TARGET ${target} + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ) + set_property(TARGET ${target} PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${include_dirs}") +endfunction() -if (ZSTD_FOUND) +if (ZSTD_FOUND AND NOT BOOST_IOSTREAMS_HAS_ZSTD) add_subdirectory(boost-zstd) + mark_as_system_target(boost-zstd) endif() + +add_subdirectory(robin-map) + +mark_as_system_target(robin_map) diff --git a/3rdparty/catch.hpp b/3rdparty/catch.hpp deleted file mode 100644 index de61226c..00000000 --- a/3rdparty/catch.hpp +++ /dev/null @@ -1,9416 +0,0 @@ -/* - * Catch v1.2.1 - * Generated: 2015-06-30 18:23:27.961086 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - -#define TWOBLUECUBES_CATCH_HPP_INCLUDED - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// #included from: internal/catch_suppress_warnings.h - -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wc++98-compat" -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -# pragma clang diagnostic ignored "-Wswitch-enum" -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wpadded" -#endif - -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -#endif - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED - -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED - -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) - -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) - -#include -#include -#include - -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED - -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler -// The following features are defined: -// -// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? -// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported - -// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 - -#ifdef __clang__ - -# if __has_feature(cxx_nullptr) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# if __has_feature(cxx_noexcept) -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ - -#endif // __BORLANDC__ - -//////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#endif // __EDG_VERSION__ - -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ - -#endif // __DMC__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -#endif - -#endif // __GNUC__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -#if (_MSC_VER >= 1600) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -#endif - -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#endif - -#endif // _MSC_VER - -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS - -#endif - -//////////////////////////////////////////////////////////////////////////////// -// C++ language feature support - -// catch all support for C++11 -#if (__cplusplus >= 201103L) - -# define CATCH_CPP11_OR_GREATER - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# endif - -# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# endif - -#endif // __cplusplus >= 201103L - -// Now set the actual defines based on the above + anything the user has configured -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NULLPTR -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_IS_ENUM -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TUPLE -#endif -#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -#define CATCH_CONFIG_VARIADIC_MACROS -#endif - -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) -#else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) -#endif - -namespace Catch { - - class NonCopyable { -#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif - - protected: - NonCopyable() {} - virtual ~NonCopyable(); - }; - - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template - inline void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template - inline void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; - - struct SourceLineInfo { - - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); - SourceLineInfo( SourceLineInfo const& other ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - bool operator < ( SourceLineInfo const& other ) const; - - std::string file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() { - return std::string(); - } - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); - -#include - -namespace Catch { - - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - NotImplementedException( NotImplementedException const& ) {} - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; - }; - -} // end namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) - -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED - -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED - -#include - -namespace Catch { - - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; - }; - - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); - - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; - }; - - IGeneratorsForTest* createGeneratorsForTest(); - -} // end namespace Catch - -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template - class Ptr { - public: - Ptr() : m_p( NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } - T& operator*() const { return *m_p; } - T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } - - private: - T* m_p; - }; - - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; - - template - struct SharedImpl : T { - - SharedImpl() : m_rc( 0 ){} - - virtual void addRef() const { - ++m_rc; - } - virtual void release() const { - if( --m_rc == 0 ) - delete this; - } - - mutable unsigned int m_rc; - }; - -} // end namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#include -#include -#include - -namespace Catch { - - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); - -} - -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED - -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED - -#include - -namespace Catch { - - class TestSpec; - - struct ITestCase : IShared { - virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - - }; -} - -namespace Catch { - -template -class MethodTestCase : public SharedImpl { - -public: - MethodTestCase( void (C::*method)() ) : m_method( method ) {} - - virtual void invoke() const { - C obj; - (obj.*m_method)(); - } - -private: - virtual ~MethodTestCase() {} - - void (C::*m_method)(); -}; - -typedef void(*TestFunction)(); - -struct NameAndDesc { - NameAndDesc( const char* _name = "", const char* _description= "" ) - : name( _name ), description( _description ) - {} - - const char* name; - const char* description; -}; - -struct AutoReg { - - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); - - template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } - - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); - - ~AutoReg(); - -private: - AutoReg( AutoReg const& ); - void operator= ( AutoReg const& ); -}; - -} // end namespace Catch - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE( ... ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ - namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ - } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() - -#else - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ - namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ - } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() - -#endif - -// #included from: internal/catch_capture.hpp -#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED - -// #included from: catch_result_builder.h -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED - -// #included from: catch_result_type.h -#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - inline bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - inline bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch - -// #included from: catch_assertionresult.h -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED - -#include - -namespace Catch { - - struct AssertionInfo - { - AssertionInfo() {} - AssertionInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ); - - std::string macroName; - SourceLineInfo lineInfo; - std::string capturedExpression; - ResultDisposition::Flags resultDisposition; - }; - - struct AssertionResultData - { - AssertionResultData() : resultType( ResultWas::Unknown ) {} - - std::string reconstructedExpression; - std::string message; - ResultWas::OfType resultType; - }; - - class AssertionResult { - public: - AssertionResult(); - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - ~AssertionResult(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - AssertionResult( AssertionResult const& ) = default; - AssertionResult( AssertionResult && ) = default; - AssertionResult& operator = ( AssertionResult const& ) = default; - AssertionResult& operator = ( AssertionResult && ) = default; -# endif - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; - - protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -namespace Catch { - - struct TestFailureException{}; - - template class ExpressionLhs; - - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - - struct CopyableStream { - CopyableStream() {} - CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& operator=( CopyableStream const& other ) { - oss.str(""); - oss << other.oss.str(); - return *this; - } - std::ostringstream oss; - }; - - class ResultBuilder { - public: - ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); - - template - ExpressionLhs operator <= ( T const& operand ); - ExpressionLhs operator <= ( bool value ); - - template - ResultBuilder& operator << ( T const& value ) { - m_stream.oss << value; - return *this; - } - - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); - - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - ResultBuilder& setLhs( std::string const& lhs ); - ResultBuilder& setRhs( std::string const& rhs ); - ResultBuilder& setOp( std::string const& op ); - - void endExpression(); - - std::string reconstructExpression() const; - AssertionResult build() const; - - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; - - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - struct ExprComponents { - ExprComponents() : testFalse( false ) {} - bool testFalse; - std::string lhs, rhs, op; - } m_exprComponents; - CopyableStream m_stream; - - bool m_shouldDebugBreak; - bool m_shouldThrow; - }; - -} // namespace Catch - -// Include after due to circular dependency: -// #included from: catch_expression_lhs.hpp -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED - -// #included from: catch_evaluate.hpp -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#endif - -#include - -namespace Catch { -namespace Internal { - - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; - - template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; - template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; - template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; - - template - inline T& opCast(T const& t) { return const_cast(t); } - -// nullptr_t support based on pull request #154 from Konstantin Baumann -#ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR - - // So the compare overloads can be operator agnostic we convey the operator as a template - // enum, which is used to specialise an Evaluator for doing the comparison. - template - class Evaluator{}; - - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs) { - return opCast( lhs ) == opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) != opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) < opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) > opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) >= opCast( rhs ); - } - }; - template - struct Evaluator { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) <= opCast( rhs ); - } - }; - - template - bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // This level of indirection allows us to specialise for integer types - // to avoid signed/ unsigned warnings - - // "base" overload - template - bool compare( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // unsigned X to int - template bool compare( unsigned int lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // unsigned X to long - template bool compare( unsigned int lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // int to unsigned X - template bool compare( int lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // long to unsigned X - template bool compare( long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long (when comparing against NULL) - template bool compare( long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - - // pointer to int (when comparing against NULL) - template bool compare( int lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, int rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - -#ifdef CATCH_CONFIG_CPP11_NULLPTR - // pointer to nullptr_t (when comparing against nullptr) - template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); - } - template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); - } -#endif // CATCH_CONFIG_CPP11_NULLPTR - -} // end of namespace Internal -} // end of namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// #included from: catch_tostring.h -#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED - -#include -#include -#include -#include -#include - -#ifdef __OBJC__ -// #included from: catch_objc_arc.hpp -#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED - -#import - -#ifdef __has_feature -#define CATCH_ARC_ENABLED __has_feature(objc_arc) -#else -#define CATCH_ARC_ENABLED 0 -#endif - -void arcSafeRelease( NSObject* obj ); -id performOptionalSelector( id obj, SEL sel ); - -#if !CATCH_ARC_ENABLED -inline void arcSafeRelease( NSObject* obj ) { - [obj release]; -} -inline id performOptionalSelector( id obj, SEL sel ) { - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; - return nil; -} -#define CATCH_UNSAFE_UNRETAINED -#define CATCH_ARC_STRONG -#else -inline void arcSafeRelease( NSObject* ){} -inline id performOptionalSelector( id obj, SEL sel ) { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" -#endif - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - return nil; -} -#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained -#define CATCH_ARC_STRONG __strong -#endif - -#endif - -#ifdef CATCH_CONFIG_CPP11_TUPLE -#include -#endif - -#ifdef CATCH_CONFIG_CPP11_IS_ENUM -#include -#endif - -namespace Catch { - -// Why we're here. -template -std::string toString( T const& value ); - -// Built in overloads - -std::string toString( std::string const& value ); -std::string toString( std::wstring const& value ); -std::string toString( const char* const value ); -std::string toString( char* const value ); -std::string toString( const wchar_t* const value ); -std::string toString( wchar_t* const value ); -std::string toString( int value ); -std::string toString( unsigned long value ); -std::string toString( unsigned int value ); -std::string toString( const double value ); -std::string toString( const float value ); -std::string toString( bool value ); -std::string toString( char value ); -std::string toString( signed char value ); -std::string toString( unsigned char value ); - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ); -#endif - -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); - std::string toString( NSObject* const& nsObject ); -#endif - -namespace Detail { - - extern std::string unprintableString; - - struct BorgType { - template BorgType( T const& ); - }; - - struct TrueType { char sizer[1]; }; - struct FalseType { char sizer[2]; }; - - TrueType& testStreamable( std::ostream& ); - FalseType testStreamable( FalseType ); - - FalseType operator<<( std::ostream const&, BorgType const& ); - - template - struct IsStreamInsertable { - static std::ostream &s; - static T const&t; - enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; - }; - -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template::value - > - struct EnumStringMaker - { - static std::string convert( T const& ) { return unprintableString; } - }; - - template - struct EnumStringMaker - { - static std::string convert( T const& v ) - { - return ::Catch::toString( - static_cast::type>(v) - ); - } - }; -#endif - template - struct StringMakerBase { -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template - static std::string convert( T const& v ) - { - return EnumStringMaker::convert( v ); - } -#else - template - static std::string convert( T const& ) { return unprintableString; } -#endif - }; - - template<> - struct StringMakerBase { - template - static std::string convert( T const& _value ) { - std::ostringstream oss; - oss << _value; - return oss.str(); - } - }; - - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - inline std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - -} // end namespace Detail - -template -struct StringMaker : - Detail::StringMakerBase::value> {}; - -template -struct StringMaker { - template - static std::string convert( U* p ) { - if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); - else - return Detail::rawMemoryToString( p ); - } -}; - -template -struct StringMaker { - static std::string convert( R C::* p ) { - if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); - else - return Detail::rawMemoryToString( p ); - } -}; - -namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ); -} - -//template -//struct StringMaker > { -// static std::string convert( std::vector const& v ) { -// return Detail::rangeToString( v.begin(), v.end() ); -// } -//}; - -template -std::string toString( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); -} - -#ifdef CATCH_CONFIG_CPP11_TUPLE - -// toString for tuples -namespace TupleDetail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct ElementPrinter { - static void print( const Tuple& tuple, std::ostream& os ) - { - os << ( N ? ", " : " " ) - << Catch::toString(std::get(tuple)); - ElementPrinter::print(tuple,os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct ElementPrinter { - static void print( const Tuple&, std::ostream& ) {} - }; - -} - -template -struct StringMaker> { - - static std::string convert( const std::tuple& tuple ) - { - std::ostringstream os; - os << '{'; - TupleDetail::ElementPrinter>::print( tuple, os ); - os << " }"; - return os.str(); - } -}; -#endif // CATCH_CONFIG_CPP11_TUPLE - -namespace Detail { - template - std::string makeString( T const& value ) { - return StringMaker::convert( value ); - } -} // end namespace Detail - -/// \brief converts any type to a string -/// -/// The default template forwards on to ostringstream - except when an -/// ostringstream overload does not exist - in which case it attempts to detect -/// that and writes {?}. -/// Overload (not specialise) this template for custom typs that you don't want -/// to provide an ostream overload for. -template -std::string toString( T const& value ) { - return StringMaker::convert( value ); -} - - namespace Detail { - template - std::string rangeToString( InputIterator first, InputIterator last ) { - std::ostringstream oss; - oss << "{ "; - if( first != last ) { - oss << Catch::toString( *first ); - for( ++first ; first != last ; ++first ) - oss << ", " << Catch::toString( *first ); - } - oss << " }"; - return oss.str(); - } -} - -} // end namespace Catch - -namespace Catch { - -// Wraps the LHS of an expression and captures the operator and RHS (if any) - -// wrapping them all in a ResultBuilder object -template -class ExpressionLhs { - ExpressionLhs& operator = ( ExpressionLhs const& ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - ExpressionLhs& operator = ( ExpressionLhs && ) = delete; -# endif - -public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - ExpressionLhs( ExpressionLhs const& ) = default; - ExpressionLhs( ExpressionLhs && ) = default; -# endif - - template - ResultBuilder& operator == ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator != ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator < ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator > ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator <= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - ResultBuilder& operator >= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - ResultBuilder& operator == ( bool rhs ) { - return captureExpression( rhs ); - } - - ResultBuilder& operator != ( bool rhs ) { - return captureExpression( rhs ); - } - - void endExpression() { - bool value = m_lhs ? true : false; - m_rb - .setLhs( Catch::toString( value ) ) - .setResultType( value ) - .endExpression(); - } - - // Only simple binary expressions are allowed on the LHS. - // If more complex compositions are required then place the sub expression in parentheses - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); - -private: - template - ResultBuilder& captureExpression( RhsT const& rhs ) { - return m_rb - .setResultType( Internal::compare( m_lhs, rhs ) ) - .setLhs( Catch::toString( m_lhs ) ) - .setRhs( Catch::toString( rhs ) ) - .setOp( Internal::OperatorTraits::getName() ); - } - -private: - ResultBuilder& m_rb; - T m_lhs; -}; - -} // end namespace Catch - - -namespace Catch { - - template - inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { - return ExpressionLhs( *this, operand ); - } - - inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { - return ExpressionLhs( *this, value ); - } - -} // namespace Catch - -// #included from: catch_message.h -#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED - -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - std::string macroName; - SourceLineInfo lineInfo; - ResultWas::OfType type; - std::string message; - unsigned int sequence; - - bool operator == ( MessageInfo const& other ) const { - return sequence == other.sequence; - } - bool operator < ( MessageInfo const& other ) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; - - struct MessageBuilder { - MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - : m_info( macroName, lineInfo, type ) - {} - - template - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - MessageInfo m_info; - std::ostringstream m_stream; - }; - - class ScopedMessage { - public: - ScopedMessage( MessageBuilder const& builder ); - ScopedMessage( ScopedMessage const& other ); - ~ScopedMessage(); - - MessageInfo m_info; - }; - -} // end namespace Catch - -// #included from: catch_interfaces_capture.h -#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED - -#include - -namespace Catch { - - class TestCase; - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct MessageInfo; - class ScopedMessageBuilder; - struct Counts; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual void assertionEnded( AssertionResult const& result ) = 0; - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - - virtual void handleFatalErrorCondition( std::string const& message ) = 0; - }; - - IResultCapture& getResultCapture(); -} - -// #included from: catch_debugger.h -#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED - -// #included from: catch_platform.h -#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED - -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_IPHONE -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -#define CATCH_PLATFORM_WINDOWS -#endif - -#include - -namespace Catch{ - - bool isDebuggerActive(); - void writeToDebugConsole( std::string const& text ); -} - -#ifdef CATCH_PLATFORM_MAC - - // The following code snippet based on: - // http://cocoawithlove.com/2008/03/break-into-debugger.html - #ifdef DEBUG - #if defined(__ppc64__) || defined(__ppc__) - #define CATCH_BREAK_INTO_DEBUGGER() \ - if( Catch::isDebuggerActive() ) { \ - __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ - : : : "memory","r0","r3","r4" ); \ - } - #else - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} - #endif - #endif - -#elif defined(_MSC_VER) - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } -#endif - -#ifndef CATCH_BREAK_INTO_DEBUGGER -#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif - -// #included from: catch_interfaces_runner.h -#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED - -namespace Catch { - class TestCase; - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// In the event of a failure works out if the debugger needs to be invoked -// and/or an exception thrown and takes appropriate action. -// This needs to be done as a macro so the debugger will stop in the user -// source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - try { \ - ( __catchResult <= expr ).endExpression(); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( Catch::getResultCapture().getLastResult()->succeeded() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( !Catch::getResultCapture().getLastResult()->succeeded() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ - try { \ - expr; \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( exceptionType ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -/////////////////////////////////////////////////////////////////////////////// -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#else - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << log + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#endif - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( log, macroName ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ - try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ - __catchResult \ - .setLhs( Catch::toString( arg ) ) \ - .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ - .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ - __catchResult.captureExpression(); \ - } catch( ... ) { \ - __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -// #included from: internal/catch_section.h -#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED - -// #included from: catch_section_info.h -#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED - -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -// #included from: catch_totals.hpp -#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED - -#include - -namespace Catch { - - struct Counts { - Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} - - Counts operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - Counts& operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } - - std::size_t total() const { - return passed + failed + failedButOk; - } - bool allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool allOk() const { - return failed == 0; - } - - std::size_t passed; - std::size_t failed; - std::size_t failedButOk; - }; - - struct Totals { - - Totals operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - - Totals& operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Counts assertions; - Counts testCases; - }; -} - -// #included from: catch_timer.h -#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED - -#ifdef CATCH_PLATFORM_WINDOWS -typedef unsigned long long uint64_t; -#else -#include -#endif - -namespace Catch { - - class Timer { - public: - Timer() : m_ticks( 0 ) {} - void start(); - unsigned int getElapsedMicroseconds() const; - unsigned int getElapsedMilliseconds() const; - double getElapsedSeconds() const; - - private: - uint64_t m_ticks; - }; - -} // namespace Catch - -#include - -namespace Catch { - - class Section : NonCopyable { - public: - Section( SectionInfo const& info ); - ~Section(); - - // This indicates whether the section should be executed or not - operator bool() const; - - private: - SectionInfo m_info; - - std::string m_name; - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; - -} // end namespace Catch - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) -#else - #define INTERNAL_CATCH_SECTION( name, desc ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) -#endif - -// #included from: internal/catch_generators.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - -template -struct IGenerator { - virtual ~IGenerator() {} - virtual T getValue( std::size_t index ) const = 0; - virtual std::size_t size () const = 0; -}; - -template -class BetweenGenerator : public IGenerator { -public: - BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} - - virtual T getValue( std::size_t index ) const { - return m_from+static_cast( index ); - } - - virtual std::size_t size() const { - return static_cast( 1+m_to-m_from ); - } - -private: - - T m_from; - T m_to; -}; - -template -class ValuesGenerator : public IGenerator { -public: - ValuesGenerator(){} - - void add( T value ) { - m_values.push_back( value ); - } - - virtual T getValue( std::size_t index ) const { - return m_values[index]; - } - - virtual std::size_t size() const { - return m_values.size(); - } - -private: - std::vector m_values; -}; - -template -class CompositeGenerator { -public: - CompositeGenerator() : m_totalSize( 0 ) {} - - // *** Move semantics, similar to auto_ptr *** - CompositeGenerator( CompositeGenerator& other ) - : m_fileInfo( other.m_fileInfo ), - m_totalSize( 0 ) - { - move( other ); - } - - CompositeGenerator& setFileInfo( const char* fileInfo ) { - m_fileInfo = fileInfo; - return *this; - } - - ~CompositeGenerator() { - deleteAll( m_composed ); - } - - operator T () const { - size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); - - typename std::vector*>::const_iterator it = m_composed.begin(); - typename std::vector*>::const_iterator itEnd = m_composed.end(); - for( size_t index = 0; it != itEnd; ++it ) - { - const IGenerator* generator = *it; - if( overallIndex >= index && overallIndex < index + generator->size() ) - { - return generator->getValue( overallIndex-index ); - } - index += generator->size(); - } - CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); - return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so - } - - void add( const IGenerator* generator ) { - m_totalSize += generator->size(); - m_composed.push_back( generator ); - } - - CompositeGenerator& then( CompositeGenerator& other ) { - move( other ); - return *this; - } - - CompositeGenerator& then( T value ) { - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( value ); - add( valuesGen ); - return *this; - } - -private: - - void move( CompositeGenerator& other ) { - std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); - m_totalSize += other.m_totalSize; - other.m_composed.clear(); - } - - std::vector*> m_composed; - std::string m_fileInfo; - size_t m_totalSize; -}; - -namespace Generators -{ - template - CompositeGenerator between( T from, T to ) { - CompositeGenerator generators; - generators.add( new BetweenGenerator( from, to ) ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3 ){ - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - generators.add( valuesGen ); - return generators; - } - - template - CompositeGenerator values( T val1, T val2, T val3, T val4 ) { - CompositeGenerator generators; - ValuesGenerator* valuesGen = new ValuesGenerator(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - valuesGen->add( val4 ); - generators.add( valuesGen ); - return generators; - } - -} // end namespace Generators - -using namespace Generators; - -} // end namespace Catch - -#define INTERNAL_CATCH_LINESTR2( line ) #line -#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) - -#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) - -// #included from: internal/catch_interfaces_exception.h -#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED - -#include -// #included from: catch_interfaces_registry_hub.h -#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED - -#include - -namespace Catch { - - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - - struct IRegistryHub { - virtual ~IRegistryHub(); - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; - }; - - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - }; - - IRegistryHub& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - - -namespace Catch { - - typedef std::string(*exceptionTranslateFunction)(); - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: - - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} - - virtual std::string translate() const { - try { - throw; - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } - - protected: - std::string(*m_translateFunction)( T& ); - }; - - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) - -// #included from: internal/catch_approx.hpp -#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED - -#include -#include - -namespace Catch { -namespace Detail { - - class Approx { - public: - explicit Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_scale( 1.0 ), - m_value( value ) - {} - - Approx( Approx const& other ) - : m_epsilon( other.m_epsilon ), - m_scale( other.m_scale ), - m_value( other.m_value ) - {} - - static Approx custom() { - return Approx( 0 ); - } - - Approx operator()( double value ) { - Approx approx( value ); - approx.epsilon( m_epsilon ); - approx.scale( m_scale ); - return approx; - } - - friend bool operator == ( double lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); - } - - friend bool operator == ( Approx const& lhs, double rhs ) { - return operator==( rhs, lhs ); - } - - friend bool operator != ( double lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - friend bool operator != ( Approx const& lhs, double rhs ) { - return !operator==( rhs, lhs ); - } - - Approx& epsilon( double newEpsilon ) { - m_epsilon = newEpsilon; - return *this; - } - - Approx& scale( double newScale ) { - m_scale = newScale; - return *this; - } - - std::string toString() const { - std::ostringstream oss; - oss << "Approx( " << Catch::toString( m_value ) << " )"; - return oss.str(); - } - - private: - double m_epsilon; - double m_scale; - double m_value; - }; -} - -template<> -inline std::string toString( Detail::Approx const& value ) { - return value.toString(); -} - -} // end namespace Catch - -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; - } - - std::string m_str; - }; - - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} - - virtual ~Contains(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } - -} // namespace Matchers - -using namespace Matchers; - -} // namespace Catch - -// #included from: internal/catch_interfaces_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED - -// #included from: catch_tag_alias.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED - -#include - -namespace Catch { - - struct TagAlias { - TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} - - std::string tag; - SourceLineInfo lineInfo; - }; - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } -// #included from: catch_option.hpp -#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED - -namespace Catch { - - // An optional type - template - class Option { - public: - Option() : nullableValue( NULL ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) - {} - - ~Option() { - reset(); - } - - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = NULL; - } - - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } - - bool operator !() const { return nullableValue == NULL; } - operator SafeBool::type() const { - return SafeBool::makeSafe( some() ); - } - - private: - T* nullableValue; - char storage[sizeof(T)]; - }; - -} // end namespace Catch - -namespace Catch { - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - virtual Option find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch - -// These files are included here so the single_include script doesn't put them -// in the conditionally compiled sections -// #included from: internal/catch_test_case_info.h -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED - -#include -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - struct ITestCase; - - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4 - }; - - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set const& _tags, - SourceLineInfo const& _lineInfo ); - - TestCaseInfo( TestCaseInfo const& other ); - - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; - - std::string name; - std::string className; - std::string description; - std::set tags; - std::set lcaseTags; - std::string tagsAsString; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; - - class TestCase : public TestCaseInfo { - public: - - TestCase( ITestCase* testCase, TestCaseInfo const& info ); - TestCase( TestCase const& other ); - - TestCase withName( std::string const& _newName ) const; - - void invoke() const; - - TestCaseInfo const& getTestCaseInfo() const; - - void swap( TestCase& other ); - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; - TestCase& operator = ( TestCase const& other ); - - private: - Ptr test; - }; - - TestCase makeTestCase( ITestCase* testCase, - std::string const& className, - std::string const& name, - std::string const& description, - SourceLineInfo const& lineInfo ); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - - -#ifdef __OBJC__ -// #included from: internal/catch_objc.hpp -#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED - -#import - -#include - -// NB. Any general catch headers included here must be included -// in catch.hpp first to make sure they are included by the single -// header for non obj-usage - -/////////////////////////////////////////////////////////////////////////////// -// This protocol is really only here for (self) documenting purposes, since -// all its methods are optional. -@protocol OcFixture - -@optional - --(void) setUp; --(void) tearDown; - -@end - -namespace Catch { - - class OcMethod : public SharedImpl { - - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - - virtual void invoke() const { - id obj = [[m_cls alloc] init]; - - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); - - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} - - Class m_cls; - SEL m_sel; - }; - - namespace Detail{ - - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } - - inline size_t registerTestMethods() { - size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); - - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); - - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); - - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); - noTestMethods++; - } - } - free(methods); - } - } - return noTestMethods; - } - - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { - - template - struct StringHolder : MatcherImpl{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } - - NSString* m_substr; - }; - - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } - - virtual std::string toString() const { - return "equals string: " + Catch::toString( m_substr ); - } - }; - - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } - - virtual std::string toString() const { - return "contains string: " + Catch::toString( m_substr ); - } - }; - - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } - - virtual std::string toString() const { - return "starts with: " + Catch::toString( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} - - virtual bool match( ExpressionType const& str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } - - virtual std::string toString() const { - return "ends with: " + Catch::toString( m_substr ); - } - }; - - } // namespace NSStringMatchers - } // namespace Impl - - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } - - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } - - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } - - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } - - } // namespace Matchers - - using namespace Matchers; - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define OC_TEST_CASE( name, desc )\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ -{\ -return @ name; \ -}\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ -{ \ -return @ desc; \ -} \ --(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) - -#endif - -#ifdef CATCH_IMPL -// #included from: internal/catch_impl.hpp -#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED - -// Collect all the implementation files together here -// These are the equivalent of what would usually be cpp files - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// #included from: ../catch_runner.hpp -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -// #included from: internal/catch_commandline.hpp -#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED - -// #included from: catch_config.hpp -#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED - -// #included from: catch_test_spec_parser.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// #included from: catch_test_spec.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -#include -#include - -namespace Catch { - - class TestSpec { - struct Pattern : SharedImpl<> { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } - private: - std::string m_name; - WildcardPosition m_wildcard; - }; - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); - } - private: - std::string m_tag; - }; - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - private: - Ptr m_underlyingPattern; - }; - - struct Filter { - std::vector > m_patterns; - - bool matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) - if( !(*it)->matches( testCase ) ) - return false; - return true; - } - }; - - public: - bool hasFilters() const { - return !m_filters.empty(); - } - bool matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) - if( it->matches( testCase ) ) - return true; - return false; - } - - private: - std::vector m_filters; - - friend class TestSpecParser; - }; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace Catch { - - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag }; - Mode m_mode; - bool m_exclusion; - std::size_t m_start, m_pos; - std::string m_arg; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases; - - public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec testSpec() { - addFilter(); - return m_testSpec; - } - private: - void visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - } - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - template - void addPattern() { - std::string token = subString(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - Ptr pattern = new T( token ); - if( m_exclusion ) - pattern = new TestSpec::ExcludedPattern( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; - } - void addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } - }; - inline TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// #included from: catch_interfaces_config.h -#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED - -#include -#include -#include - -namespace Catch { - - struct Verbosity { enum Level { - NoOutput = 0, - Quiet, - Normal - }; }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - - class TestSpec; - - struct IConfig : IShared { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual bool forceColour() const = 0; - }; -} - -// #included from: catch_stream.h -#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED - -#include - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - class Stream { - public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; - }; - - std::ostream& cout(); - std::ostream& cerr(); -} - -#include -#include -#include -#include -#include - -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct ConfigData { - - ConfigData() - : listTests( false ), - listTags( false ), - listReporters( false ), - listTestNamesOnly( false ), - showSuccessfulTests( false ), - shouldDebugBreak( false ), - noThrow( false ), - showHelp( false ), - showInvisibles( false ), - forceColour( false ), - abortAfter( -1 ), - rngSeed( 0 ), - verbosity( Verbosity::Normal ), - warnings( WarnAbout::Nothing ), - showDurations( ShowDurations::DefaultForReporter ), - runOrder( RunTests::InDeclarationOrder ) - {} - - bool listTests; - bool listTags; - bool listReporters; - bool listTestNamesOnly; - - bool showSuccessfulTests; - bool shouldDebugBreak; - bool noThrow; - bool showHelp; - bool showInvisibles; - bool forceColour; - - int abortAfter; - unsigned int rngSeed; - - Verbosity::Level verbosity; - WarnAbout::What warnings; - ShowDurations::OrNot showDurations; - RunTests::InWhatOrder runOrder; - - std::string reporterName; - std::string outputFilename; - std::string name; - std::string processName; - - std::vector testsOrTags; - }; - - class Config : public SharedImpl { - private: - Config( Config const& other ); - Config& operator = ( Config const& other ); - virtual void dummy(); - public: - - Config() - : m_os( Catch::cout().rdbuf() ) - {} - - Config( ConfigData const& data ) - : m_data( data ), - m_os( Catch::cout().rdbuf() ) - { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) - parser.parse( data.testsOrTags[i] ); - m_testSpec = parser.testSpec(); - } - } - - virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; - } - - std::string const& getFilename() const { - return m_data.outputFilename ; - } - - bool listTests() const { return m_data.listTests; } - bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool listTags() const { return m_data.listTags; } - bool listReporters() const { return m_data.listReporters; } - - std::string getProcessName() const { return m_data.processName; } - - bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } - - int abortAfter() const { return m_data.abortAfter; } - - TestSpec const& testSpec() const { return m_testSpec; } - - bool showHelp() const { return m_data.showHelp; } - bool showInvisibles() const { return m_data.showInvisibles; } - - // IConfig interface - virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } - virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } - virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } - virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } - virtual unsigned int rngSeed() const { return m_data.rngSeed; } - virtual bool forceColour() const { return m_data.forceColour; } - - private: - ConfigData m_data; - - Stream m_stream; - mutable std::ostream m_os; - TestSpec m_testSpec; - }; - -} // end namespace Catch - -// #included from: catch_clara.h -#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH -#undef CLARA_CONFIG_CONSOLE_WIDTH -#endif -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -// Declare Clara inside the Catch namespace -#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { -// #included from: ../external/clara.h - -// Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) - -#ifndef STITCH_CLARA_OPEN_NAMESPACE -#define TWOBLUECUBES_CLARA_H_INCLUDED -#define STITCH_CLARA_OPEN_NAMESPACE -#define STITCH_CLARA_CLOSE_NAMESPACE -#else -#define STITCH_CLARA_CLOSE_NAMESPACE } -#endif - -#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE - -// ----------- #included from tbc_text_format.h ----------- - -// Only use header guard if we are not using an outer namespace -#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) -#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -#define TBC_TEXT_FORMAT_H_INCLUDED -#endif - -#include -#include -#include - -// Use optional outer namespace -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Tbc - -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TBC_TEXT_FORMAT_H_INCLUDED - -// ----------- end of #include from tbc_text_format.h ----------- -// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h - -#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE - -#include -#include -#include -#include - -// Use optional outer namespace -#ifdef STITCH_CLARA_OPEN_NAMESPACE -STITCH_CLARA_OPEN_NAMESPACE -#endif - -namespace Clara { - - struct UnpositionalTag {}; - - extern UnpositionalTag _; - -#ifdef CLARA_CONFIG_MAIN - UnpositionalTag _; -#endif - - namespace Detail { - -#ifdef CLARA_CONSOLE_WIDTH - const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - using namespace Tbc; - - inline bool startsWith( std::string const& str, std::string const& prefix ) { - return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; - } - - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - template struct RemoveConstRef{ typedef T type; }; - - template struct IsBool { static const bool value = false; }; - template<> struct IsBool { static const bool value = true; }; - - template - void convertInto( std::string const& _source, T& _dest ) { - std::stringstream ss; - ss << _source; - ss >> _dest; - if( ss.fail() ) - throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); - } - inline void convertInto( std::string const& _source, std::string& _dest ) { - _dest = _source; - } - inline void convertInto( std::string const& _source, bool& _dest ) { - std::string sourceLC = _source; - std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); - if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) - _dest = true; - else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) - _dest = false; - else - throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); - } - inline void convertInto( bool _source, bool& _dest ) { - _dest = _source; - } - template - inline void convertInto( bool, T& ) { - throw std::runtime_error( "Invalid conversion" ); - } - - template - struct IArgFunction { - virtual ~IArgFunction() {} -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - IArgFunction() = default; - IArgFunction( IArgFunction const& ) = default; -# endif - virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual void setFlag( ConfigT& config ) const = 0; - virtual bool takesArg() const = 0; - virtual IArgFunction* clone() const = 0; - }; - - template - class BoundArgFunction { - public: - BoundArgFunction() : functionObj( NULL ) {} - BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} - BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; - delete functionObj; - functionObj = newFunctionObj; - return *this; - } - ~BoundArgFunction() { delete functionObj; } - - void set( ConfigT& config, std::string const& value ) const { - functionObj->set( config, value ); - } - void setFlag( ConfigT& config ) const { - functionObj->setFlag( config ); - } - bool takesArg() const { return functionObj->takesArg(); } - - bool isSet() const { - return functionObj != NULL; - } - private: - IArgFunction* functionObj; - }; - - template - struct NullBinder : IArgFunction{ - virtual void set( C&, std::string const& ) const {} - virtual void setFlag( C& ) const {} - virtual bool takesArg() const { return true; } - virtual IArgFunction* clone() const { return new NullBinder( *this ); } - }; - - template - struct BoundDataMember : IArgFunction{ - BoundDataMember( M C::* _member ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - convertInto( stringValue, p.*member ); - } - virtual void setFlag( C& p ) const { - convertInto( true, p.*member ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } - M C::* member; - }; - template - struct BoundUnaryMethod : IArgFunction{ - BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - (p.*member)( value ); - } - virtual void setFlag( C& p ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - (p.*member)( value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } - void (C::*member)( M ); - }; - template - struct BoundNullaryMethod : IArgFunction{ - BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - (p.*member)(); - } - virtual void setFlag( C& p ) const { - (p.*member)(); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } - void (C::*member)(); - }; - - template - struct BoundUnaryFunction : IArgFunction{ - BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - function( obj ); - } - virtual void setFlag( C& p ) const { - function( p ); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } - void (*function)( C& ); - }; - - template - struct BoundBinaryFunction : IArgFunction{ - BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - typename RemoveConstRef::type value; - convertInto( stringValue, value ); - function( obj, value ); - } - virtual void setFlag( C& obj ) const { - typename RemoveConstRef::type value; - convertInto( true, value ); - function( obj, value ); - } - virtual bool takesArg() const { return !IsBool::value; } - virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } - void (*function)( C&, T ); - }; - - } // namespace Detail - - struct Parser { - Parser() : separators( " \t=:" ) {} - - struct Token { - enum Type { Positional, ShortOpt, LongOpt }; - Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} - Type type; - std::string data; - }; - - void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { - const std::string doubleDash = "--"; - for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) - parseIntoTokens( argv[i] , tokens); - } - void parseIntoTokens( std::string arg, std::vector& tokens ) const { - while( !arg.empty() ) { - Parser::Token token( Parser::Token::Positional, arg ); - arg = ""; - if( token.data[0] == '-' ) { - if( token.data.size() > 1 && token.data[1] == '-' ) { - token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); - } - else { - token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); - if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { - arg = "-" + token.data.substr( 1 ); - token.data = token.data.substr( 0, 1 ); - } - } - } - if( token.type != Parser::Token::Positional ) { - std::size_t pos = token.data.find_first_of( separators ); - if( pos != std::string::npos ) { - arg = token.data.substr( pos+1 ); - token.data = token.data.substr( 0, pos ); - } - } - tokens.push_back( token ); - } - } - std::string separators; - }; - - template - struct CommonArgProperties { - CommonArgProperties() {} - CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} - - Detail::BoundArgFunction boundField; - std::string description; - std::string detail; - std::string placeholder; // Only value if boundField takes an arg - - bool takesArg() const { - return !placeholder.empty(); - } - void validate() const { - if( !boundField.isSet() ) - throw std::logic_error( "option not bound" ); - } - }; - struct OptionArgProperties { - std::vector shortNames; - std::string longName; - - bool hasShortName( std::string const& shortName ) const { - return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); - } - bool hasLongName( std::string const& _longName ) const { - return _longName == longName; - } - }; - struct PositionalArgProperties { - PositionalArgProperties() : position( -1 ) {} - int position; // -1 means non-positional (floating) - - bool isFixedPositional() const { - return position != -1; - } - }; - - template - class CommandLine { - - struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { - Arg() {} - Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} - - using CommonArgProperties::placeholder; // !TBD - - std::string dbgName() const { - if( !longName.empty() ) - return "--" + longName; - if( !shortNames.empty() ) - return "-" + shortNames[0]; - return "positional args"; - } - std::string commands() const { - std::ostringstream oss; - bool first = true; - std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); - for(; it != itEnd; ++it ) { - if( first ) - first = false; - else - oss << ", "; - oss << "-" << *it; - } - if( !longName.empty() ) { - if( !first ) - oss << ", "; - oss << "--" << longName; - } - if( !placeholder.empty() ) - oss << " <" << placeholder << ">"; - return oss.str(); - } - }; - - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif - - friend void addOptName( Arg& arg, std::string const& optName ) - { - if( optName.empty() ) - return; - if( Detail::startsWith( optName, "--" ) ) { - if( !arg.longName.empty() ) - throw std::logic_error( "Only one long opt may be specified. '" - + arg.longName - + "' already specified, now attempting to add '" - + optName + "'" ); - arg.longName = optName.substr( 2 ); - } - else if( Detail::startsWith( optName, "-" ) ) - arg.shortNames.push_back( optName.substr( 1 ) ); - else - throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); - } - friend void setPositionalArg( Arg& arg, int position ) - { - arg.position = position; - } - - class ArgBuilder { - public: - ArgBuilder( Arg* arg ) : m_arg( arg ) {} - - // Bind a non-boolean data member (requires placeholder string) - template - void bind( M C::* field, std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - m_arg->placeholder = placeholder; - } - // Bind a boolean data member (no placeholder required) - template - void bind( bool C::* field ) { - m_arg->boundField = new Detail::BoundDataMember( field ); - } - - // Bind a method taking a single, non-boolean argument (requires a placeholder string) - template - void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - m_arg->placeholder = placeholder; - } - - // Bind a method taking a single, boolean argument (no placeholder string required) - template - void bind( void (C::* unaryMethod)( bool ) ) { - m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); - } - - // Bind a method that takes no arguments (will be called if opt is present) - template - void bind( void (C::* nullaryMethod)() ) { - m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); - } - - // Bind a free function taking a single argument - the object to operate on (no placeholder string required) - template - void bind( void (* unaryFunction)( C& ) ) { - m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); - } - - // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) - template - void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); - m_arg->placeholder = placeholder; - } - - ArgBuilder& describe( std::string const& description ) { - m_arg->description = description; - return *this; - } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; - return *this; - } - - protected: - Arg* m_arg; - }; - - class OptBuilder : public ArgBuilder { - public: - OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} - OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} - - OptBuilder& operator[]( std::string const& optName ) { - addOptName( *ArgBuilder::m_arg, optName ); - return *this; - } - }; - - public: - - CommandLine() - : m_boundProcessName( new Detail::NullBinder() ), - m_highestSpecifiedArgPosition( 0 ), - m_throwOnUnrecognisedTokens( false ) - {} - CommandLine( CommandLine const& other ) - : m_boundProcessName( other.m_boundProcessName ), - m_options ( other.m_options ), - m_positionalArgs( other.m_positionalArgs ), - m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), - m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) - { - if( other.m_floatingArg.get() ) - m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); - } - - CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { - m_throwOnUnrecognisedTokens = shouldThrow; - return *this; - } - - OptBuilder operator[]( std::string const& optName ) { - m_options.push_back( Arg() ); - addOptName( m_options.back(), optName ); - OptBuilder builder( &m_options.back() ); - return builder; - } - - ArgBuilder operator[]( int position ) { - m_positionalArgs.insert( std::make_pair( position, Arg() ) ); - if( position > m_highestSpecifiedArgPosition ) - m_highestSpecifiedArgPosition = position; - setPositionalArg( m_positionalArgs[position], position ); - ArgBuilder builder( &m_positionalArgs[position] ); - return builder; - } - - // Invoke this with the _ instance - ArgBuilder operator[]( UnpositionalTag ) { - if( m_floatingArg.get() ) - throw std::logic_error( "Only one unpositional argument can be added" ); - m_floatingArg.reset( new Arg() ); - ArgBuilder builder( m_floatingArg.get() ); - return builder; - } - - template - void bindProcessName( M C::* field ) { - m_boundProcessName = new Detail::BoundDataMember( field ); - } - template - void bindProcessName( void (C::*_unaryMethod)( M ) ) { - m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); - } - - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { - typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; - std::size_t maxWidth = 0; - for( it = itBegin; it != itEnd; ++it ) - maxWidth = (std::max)( maxWidth, it->commands().size() ); - - for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() - .setWidth( maxWidth+indent ) - .setIndent( indent ) ); - Detail::Text desc( it->description, Detail::TextAttributes() - .setWidth( width - maxWidth - 3 ) ); - - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; - os << usageCol; - - if( i < desc.size() && !desc[i].empty() ) - os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) - << desc[i]; - os << "\n"; - } - } - } - std::string optUsage() const { - std::ostringstream oss; - optUsage( oss ); - return oss.str(); - } - - void argSynopsis( std::ostream& os ) const { - for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { - if( i > 1 ) - os << " "; - typename std::map::const_iterator it = m_positionalArgs.find( i ); - if( it != m_positionalArgs.end() ) - os << "<" << it->second.placeholder << ">"; - else if( m_floatingArg.get() ) - os << "<" << m_floatingArg->placeholder << ">"; - else - throw std::logic_error( "non consecutive positional arguments with no floating args" ); - } - // !TBD No indication of mandatory args - if( m_floatingArg.get() ) { - if( m_highestSpecifiedArgPosition > 1 ) - os << " "; - os << "[<" << m_floatingArg->placeholder << "> ...]"; - } - } - std::string argSynopsis() const { - std::ostringstream oss; - argSynopsis( oss ); - return oss.str(); - } - - void usage( std::ostream& os, std::string const& procName ) const { - validate(); - os << "usage:\n " << procName << " "; - argSynopsis( os ); - if( !m_options.empty() ) { - os << " [options]\n\nwhere options are: \n"; - optUsage( os, 2 ); - } - os << "\n"; - } - std::string usage( std::string const& procName ) const { - std::ostringstream oss; - usage( oss, procName ); - return oss.str(); - } - - ConfigT parse( int argc, char const * const * argv ) const { - ConfigT config; - parseInto( argc, argv, config ); - return config; - } - - std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { - std::string processName = argv[0]; - std::size_t lastSlash = processName.find_last_of( "/\\" ); - if( lastSlash != std::string::npos ) - processName = processName.substr( lastSlash+1 ); - m_boundProcessName.set( config, processName ); - std::vector tokens; - Parser parser; - parser.parseIntoTokens( argc, argv, tokens ); - return populate( tokens, config ); - } - - std::vector populate( std::vector const& tokens, ConfigT& config ) const { - validate(); - std::vector unusedTokens = populateOptions( tokens, config ); - unusedTokens = populateFixedArgs( unusedTokens, config ); - unusedTokens = populateFloatingArgs( unusedTokens, config ); - return unusedTokens; - } - - std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - std::vector errors; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); - for(; it != itEnd; ++it ) { - Arg const& arg = *it; - - try { - if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || - ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { - if( arg.takesArg() ) { - if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) - errors.push_back( "Expected argument to option: " + token.data ); - else - arg.boundField.set( config, tokens[++i].data ); - } - else { - arg.boundField.setFlag( config ); - } - break; - } - } - catch( std::exception& ex ) { - errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); - } - } - if( it == itEnd ) { - if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) - unusedTokens.push_back( token ); - else if( errors.empty() && m_throwOnUnrecognisedTokens ) - errors.push_back( "unrecognised option: " + token.data ); - } - } - if( !errors.empty() ) { - std::ostringstream oss; - for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); - it != itEnd; - ++it ) { - if( it != errors.begin() ) - oss << "\n"; - oss << *it; - } - throw std::runtime_error( oss.str() ); - } - return unusedTokens; - } - std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { - std::vector unusedTokens; - int position = 1; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::map::const_iterator it = m_positionalArgs.find( position ); - if( it != m_positionalArgs.end() ) - it->second.boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - if( token.type == Parser::Token::Positional ) - position++; - } - return unusedTokens; - } - std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { - if( !m_floatingArg.get() ) - return tokens; - std::vector unusedTokens; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - if( token.type == Parser::Token::Positional ) - m_floatingArg->boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - } - return unusedTokens; - } - - void validate() const - { - if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) - throw std::logic_error( "No options or arguments specified" ); - - for( typename std::vector::const_iterator it = m_options.begin(), - itEnd = m_options.end(); - it != itEnd; ++it ) - it->validate(); - } - - private: - Detail::BoundArgFunction m_boundProcessName; - std::vector m_options; - std::map m_positionalArgs; - ArgAutoPtr m_floatingArg; - int m_highestSpecifiedArgPosition; - bool m_throwOnUnrecognisedTokens; - }; - -} // end namespace Clara - -STITCH_CLARA_CLOSE_NAMESPACE -#undef STITCH_CLARA_OPEN_NAMESPACE -#undef STITCH_CLARA_CLOSE_NAMESPACE - -#endif // TWOBLUECUBES_CLARA_H_INCLUDED -#undef STITCH_CLARA_OPEN_NAMESPACE - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -#include - -namespace Catch { - - inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } - inline void abortAfterX( ConfigData& config, int x ) { - if( x < 1 ) - throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); - config.abortAfter = x; - } - inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } - - inline void addWarning( ConfigData& config, std::string const& _warning ) { - if( _warning == "NoAssertions" ) - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); - else - throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); - } - inline void setOrder( ConfigData& config, std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); - } - inline void setRngSeed( ConfigData& config, std::string const& seed ) { - if( seed == "time" ) { - config.rngSeed = static_cast( std::time(0) ); - } - else { - std::stringstream ss; - ss << seed; - ss >> config.rngSeed; - if( ss.fail() ) - throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); - } - } - inline void setVerbosity( ConfigData& config, int level ) { - // !TBD: accept strings? - config.verbosity = static_cast( level ); - } - inline void setShowDurations( ConfigData& config, bool _showDurations ) { - config.showDurations = _showDurations - ? ShowDurations::Always - : ShowDurations::Never; - } - inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { - std::ifstream f( _filename.c_str() ); - if( !f.is_open() ) - throw std::domain_error( "Unable to load input file: " + _filename ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); - } - } - - inline Clara::CommandLine makeCommandLineParser() { - - using namespace Clara; - CommandLine cli; - - cli.bindProcessName( &ConfigData::processName ); - - cli["-?"]["-h"]["--help"] - .describe( "display usage information" ) - .bind( &ConfigData::showHelp ); - - cli["-l"]["--list-tests"] - .describe( "list all/matching test cases" ) - .bind( &ConfigData::listTests ); - - cli["-t"]["--list-tags"] - .describe( "list all/matching tags" ) - .bind( &ConfigData::listTags ); - - cli["-s"]["--success"] - .describe( "include successful tests in output" ) - .bind( &ConfigData::showSuccessfulTests ); - - cli["-b"]["--break"] - .describe( "break into debugger on failure" ) - .bind( &ConfigData::shouldDebugBreak ); - - cli["-e"]["--nothrow"] - .describe( "skip exception tests" ) - .bind( &ConfigData::noThrow ); - - cli["-i"]["--invisibles"] - .describe( "show invisibles (tabs, newlines)" ) - .bind( &ConfigData::showInvisibles ); - - cli["-o"]["--out"] - .describe( "output filename" ) - .bind( &ConfigData::outputFilename, "filename" ); - - cli["-r"]["--reporter"] -// .placeholder( "name[:filename]" ) - .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); - - cli["-n"]["--name"] - .describe( "suite name" ) - .bind( &ConfigData::name, "name" ); - - cli["-a"]["--abort"] - .describe( "abort at first failure" ) - .bind( &abortAfterFirst ); - - cli["-x"]["--abortx"] - .describe( "abort after x failures" ) - .bind( &abortAfterX, "no. failures" ); - - cli["-w"]["--warn"] - .describe( "enable warnings" ) - .bind( &addWarning, "warning name" ); - -// - needs updating if reinstated -// cli.into( &setVerbosity ) -// .describe( "level of verbosity (0=no output)" ) -// .shortOpt( "v") -// .longOpt( "verbosity" ) -// .placeholder( "level" ); - - cli[_] - .describe( "which test or tests to use" ) - .bind( &addTestOrTags, "test name, pattern or tags" ); - - cli["-d"]["--durations"] - .describe( "show test durations" ) - .bind( &setShowDurations, "yes/no" ); - - cli["-f"]["--input-file"] - .describe( "load test names to run from a file" ) - .bind( &loadTestNamesFromFile, "filename" ); - - // Less common commands which don't have a short form - cli["--list-test-names-only"] - .describe( "list all/matching test cases names only" ) - .bind( &ConfigData::listTestNamesOnly ); - - cli["--list-reporters"] - .describe( "list all reporters" ) - .bind( &ConfigData::listReporters ); - - cli["--order"] - .describe( "test case order (defaults to decl)" ) - .bind( &setOrder, "decl|lex|rand" ); - - cli["--rng-seed"] - .describe( "set a specific seed for random numbers" ) - .bind( &setRngSeed, "'time'|number" ); - - cli["--force-colour"] - .describe( "force colourised output" ) - .bind( &ConfigData::forceColour ); - - return cli; - } - -} // end namespace Catch - -// #included from: internal/catch_list.hpp -#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED - -// #included from: catch_text.h -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED - -#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch -// #included from: ../external/tbc_text_format.h -// Only use header guard if we are not using an outer namespace -#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# endif -# else -# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# endif -#endif -#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#include -#include -#include - -// Use optional outer namespace -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif - -namespace Tbc { - -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Tbc - -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif - -#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE - -namespace Catch { - using Tbc::Text; - using Tbc::TextAttributes; -} - -// #included from: catch_console_colour.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED - -namespace Catch { - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - - // By intention - FileName = LightGrey, - Warning = Yellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - - OriginalExpression = Cyan, - ReconstructedExpression = Yellow, - - SecondaryText = LightGrey, - Headers = White - }; - - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour const& other ); - ~Colour(); - - // Use static method for one-shot changes - static void use( Code _colourCode ); - - private: - bool m_moved; - }; - - inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } - -} // end namespace Catch - -// #included from: catch_interfaces_reporter.h -#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED - -#include -#include -#include -#include - -namespace Catch -{ - struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } - - private: - std::ostream* m_stream; - Ptr m_fullConfig; - }; - - struct ReporterPreferences { - ReporterPreferences() - : shouldRedirectStdOut( false ) - {} - - bool shouldRedirectStdOut; - }; - - template - struct LazyStat : Option { - LazyStat() : used( false ) {} - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ) : name( _name ) {} - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - virtual ~AssertionStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; -# endif - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - virtual ~SectionStats(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; -# endif - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - virtual ~TestCaseStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; -# endif - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - virtual ~TestGroupStats(); - -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; -# endif - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - virtual ~TestRunStats(); - -# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestRunStats( TestRunStats const& _other ) - : runInfo( _other.runInfo ), - totals( _other.totals ), - aborting( _other.aborting ) - {} -# else - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; -# endif - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - struct IStreamingReporter : IShared { - virtual ~IStreamingReporter(); - - // Implementing class must also provide the following static method: - // static std::string getDescription(); - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - }; - - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - - struct IReporterRegistry { - typedef std::map FactoryMap; - - virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - }; - -} - -#include -#include - -namespace Catch { - - inline std::size_t listTests( Config const& config ) { - - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } - - std::size_t matchedTests = 0; - TextAttributes nameAttr, tagsAttr; - nameAttr.setInitialIndent( 2 ).setIndent( 4 ); - tagsAttr.setIndent( 6 ); - - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); - - Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; - } - - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; - else - Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; - return matchedTests; - } - - inline std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; - } - return matchedTests; - } - - struct TagInfo { - TagInfo() : count ( 0 ) {} - void add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } - std::string all() const { - std::string out; - for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); - it != itEnd; - ++it ) - out += "[" + *it + "]"; - return out; - } - std::set spellings; - std::size_t count; - }; - - inline std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } - - std::map tagCounts; - - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); - for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::string lcaseTagName = toLower( tagName ); - std::map::iterator countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } - - for( std::map::const_iterator countIt = tagCounts.begin(), - countItEnd = tagCounts.end(); - countIt != countItEnd; - ++countIt ) { - std::ostringstream oss; - oss << " " << std::setw(2) << countIt->second.count << " "; - Text wrapper( countIt->second.all(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( oss.str().size() ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - Catch::cout() << oss.str() << wrapper << "\n"; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; - return tagCounts.size(); - } - - inline std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; - std::size_t maxNameLen = 0; - for(it = itBegin; it != itEnd; ++it ) - maxNameLen = (std::max)( maxNameLen, it->first.size() ); - - for(it = itBegin; it != itEnd; ++it ) { - Text wrapper( it->second->getDescription(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( 7+maxNameLen ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); - Catch::cout() << " " - << it->first - << ":" - << std::string( maxNameLen - it->first.size() + 2, ' ' ) - << wrapper << "\n"; - } - Catch::cout() << std::endl; - return factories.size(); - } - - inline Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } - -} // end namespace Catch - -// #included from: internal/catch_runner_impl.hpp -#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED - -// #included from: catch_test_case_tracker.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { -namespace SectionTracking { - - class TrackedSection { - - typedef std::map TrackedSections; - - public: - enum RunState { - NotStarted, - Executing, - ExecutingChildren, - Completed - }; - - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) - {} - - RunState runState() const { return m_runState; } - - TrackedSection* findChild( std::string const& childName ); - TrackedSection* acquireChild( std::string const& childName ); - - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; - } - void leave(); - - TrackedSection* getParent() { - return m_parent; - } - bool hasChildren() const { - return !m_children.empty(); - } - - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; - }; - - inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); - } - inline void TrackedSection::leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { - m_runState = ExecutingChildren; - return; - } - m_runState = Completed; - } - - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} - - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; - - m_currentSection = child; - m_currentSection->enter(); - return true; - } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; - } - - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } - - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); - } - ~Guard() { - m_tracker.leaveTestCase(); - } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; - - private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); - } - void leaveTestCase() { - m_testCase.leave(); - } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; - }; - -} // namespace SectionTracking - -using SectionTracking::TestCaseTracker; - -} // namespace Catch - -// #included from: catch_fatal_condition.hpp -#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED - -namespace Catch { - - // Report the error condition then exit the process - inline void fatal( std::string const& message, int exitCode ) { - IContext& context = Catch::getCurrentContext(); - IResultCapture* resultCapture = context.getResultCapture(); - resultCapture->handleFatalErrorCondition( message ); - - if( Catch::alwaysTrue() ) // avoids "no return" warnings - exit( exitCode ); - } - -} // namespace Catch - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -namespace Catch { - - struct FatalConditionHandler { - void reset() {} - }; - -} // namespace Catch - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -#include - -namespace Catch { - - struct SignalDefs { int id; const char* name; }; - extern SignalDefs signalDefs[]; - SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - struct FatalConditionHandler { - - static void handleSignal( int sig ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - if( sig == signalDefs[i].id ) - fatal( signalDefs[i].name, -sig ); - fatal( "", -sig ); - } - - FatalConditionHandler() : m_isSet( true ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, handleSignal ); - } - ~FatalConditionHandler() { - reset(); - } - void reset() { - if( m_isSet ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, SIG_DFL ); - m_isSet = false; - } - } - - bool m_isSet; - }; - -} // namespace Catch - -#endif // not Windows - -#include -#include - -namespace Catch { - - class StreamRedirect { - - public: - StreamRedirect( std::ostream& stream, std::string& targetString ) - : m_stream( stream ), - m_prevBuf( stream.rdbuf() ), - m_targetString( targetString ) - { - stream.rdbuf( m_oss.rdbuf() ); - } - - ~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf( m_prevBuf ); - } - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - RunContext( RunContext const& ); - void operator =( RunContext const& ); - - public: - - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), - m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) - { - m_context.setRunner( this ); - m_context.setConfig( m_config ); - m_context.setResultCapture( this ); - m_reporter->testRunStarting( m_runInfo ); - } - - virtual ~RunContext() { - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); - } - - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); - } - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); - } - - Totals runTest( TestCase const& testCase ) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - TestCaseInfo testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting( testInfo ); - - m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); - - do { - do { - runCurrentTest( redirectedCout, redirectedCerr ); - } - while( !m_testCaseTracker->isCompleted() && !aborting() ); - } - while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); - - Totals deltaTotals = m_totals.delta( prevTotals ); - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting() ) ); - - m_activeTestCase = NULL; - m_testCaseTracker.reset(); - - return deltaTotals; - } - - Ptr config() const { - return m_config; - } - - private: // IResultCapture - - virtual void assertionEnded( AssertionResult const& result ) { - if( result.getResultType() == ResultWas::Ok ) { - m_totals.assertions.passed++; - } - else if( !result.isOk() ) { - m_totals.assertions.failed++; - } - - if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) - m_messages.clear(); - - // Reset working state - m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); - m_lastResult = result; - } - - virtual bool sectionStarted ( - SectionInfo const& sectionInfo, - Counts& assertions - ) - { - std::ostringstream oss; - oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - - if( !m_testCaseTracker->enterSection( oss.str() ) ) - return false; - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting( sectionInfo ); - - assertions = m_totals.assertions; - - return true; - } - bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - m_testCaseTracker->leaveSection(); - - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); - m_messages.clear(); - } - - virtual void pushScopedMessage( MessageInfo const& message ) { - m_messages.push_back( message ); - } - - virtual void popScopedMessage( MessageInfo const& message ) { - m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); - } - - virtual std::string getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : ""; - } - - virtual const AssertionResult* getLastResult() const { - return &m_lastResult; - } - - virtual void handleFatalErrorCondition( std::string const& message ) { - ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); - resultBuilder.setResultType( ResultWas::FatalErrorCondition ); - resultBuilder << message; - resultBuilder.captureExpression(); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); - m_reporter->sectionEnded( testCaseSectionStats ); - - TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - "", - "", - false ) ); - m_totals.testCases.failed++; - testGroupEnded( "", m_totals, 1, 1 ); - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); - } - - public: - // !TBD We need to do this another way! - bool aborting() const { - return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); - } - - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - m_reporter->sectionStarting( testCaseSection ); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - try { - m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); - - Timer timer; - timer.start(); - if( m_reporter->getPreferences().shouldRedirectStdOut ) { - StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); - invokeActiveTestCase(); - } - else { - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } - catch( TestFailureException& ) { - // This just means the test was aborted due to failure - } - catch(...) { - makeUnexpectedResultBuilder().useActiveException(); - } - handleUnfinishedSections(); - m_messages.clear(); - - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); - - if( testCaseInfo.okToFail() ) { - std::swap( assertions.failedButOk, assertions.failed ); - m_totals.assertions.failed -= assertions.failedButOk; - m_totals.assertions.failedButOk += assertions.failedButOk; - } - - SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); - m_reporter->sectionEnded( testCaseSectionStats ); - } - - void invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - private: - - ResultBuilder makeUnexpectedResultBuilder() const { - return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression.c_str(), - m_lastAssertionInfo.resultDisposition ); - } - - void handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); - m_unfinishedSections.clear(); - } - - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase; - Option m_testCaseTracker; - AssertionResult m_lastResult; - - Ptr m_config; - Totals m_totals; - Ptr m_reporter; - std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - }; - - IResultCapture& getResultCapture() { - if( IResultCapture* capture = getCurrentContext().getResultCapture() ) - return *capture; - else - throw std::logic_error( "No result capture instance" ); - } - -} // end namespace Catch - -// #included from: internal/catch_version.h -#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED - -namespace Catch { - - // Versioning information - struct Version { - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - std::string const& _branchName, - unsigned int _buildNumber ); - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; - - // buildNumber is only used if branchName is not null - std::string const branchName; - unsigned int const buildNumber; - - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - - private: - void operator=( Version const& ); - }; - - extern Version libraryVersion; -} - -#include -#include -#include - -namespace Catch { - - class Runner { - - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); - } - - Totals runTests() { - - RunContext context( m_config.get(), m_reporter ); - - Totals totals; - - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? - - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; - } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; - - class Session : NonCopyable { - static bool alreadyInstantiated; - - public: - - struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; - - Session() - : m_cli( makeCommandLineParser() ) { - if( alreadyInstantiated ) { - std::string msg = "Only one instance of Catch::Session can ever be used"; - Catch::cerr() << msg << std::endl; - throw std::logic_error( msg ); - } - alreadyInstantiated = true; - } - ~Session() { - Catch::cleanUp(); - } - - void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion << "\n"; - - m_cli.usage( Catch::cout(), processName ); - Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; - } - - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { - try { - m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); - if( m_configData.showHelp ) - showHelp( m_configData.processName ); - m_config.reset(); - } - catch( std::exception& ex ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; - } - m_cli.usage( Catch::cout(), m_configData.processName ); - return (std::numeric_limits::max)(); - } - return 0; - } - - void useConfigData( ConfigData const& _configData ) { - m_configData = _configData; - m_config.reset(); - } - - int run( int argc, char* const argv[] ) { - - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - - int run() { - if( m_configData.showHelp ) - return 0; - - try - { - config(); // Force config to be constructed - - std::srand( m_configData.rngSeed ); - - Runner runner( m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - return static_cast( runner.runTests().assertions.failed ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return (std::numeric_limits::max)(); - } - } - - Clara::CommandLine const& cli() const { - return m_cli; - } - std::vector const& unusedTokens() const { - return m_unusedTokens; - } - ConfigData& configData() { - return m_configData; - } - Config& config() { - if( !m_config ) - m_config = new Config( m_configData ); - return *m_config; - } - - private: - Clara::CommandLine m_cli; - std::vector m_unusedTokens; - ConfigData m_configData; - Ptr m_config; - }; - - bool Session::alreadyInstantiated = false; - -} // end namespace Catch - -// #included from: catch_registry_hub.hpp -#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED - -// #included from: catch_test_case_registry_impl.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED - -#include -#include -#include -#include -#include - -namespace Catch { - - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i const& getAllTests() const { - return m_functionsInOrder; - } - - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); - } - sortTests( config, matchingTestCases ); - } - - private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; - size_t m_unnamedCount; - }; - - /////////////////////////////////////////////////////////////////////////// - - class FreeFunctionTestCase : public SharedImpl { - public: - - FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} - - virtual void invoke() const { - m_fun(); - } - - private: - virtual ~FreeFunctionTestCase(); - - TestFunction m_fun; - }; - - inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, "&" ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - - /////////////////////////////////////////////////////////////////////////// - - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); - } - - AutoReg::~AutoReg() {} - - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); - } - -} // end namespace Catch - -// #included from: catch_reporter_registry.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED - -#include - -namespace Catch { - - class ReporterRegistry : public IReporterRegistry { - - public: - - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } - - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { - FactoryMap::const_iterator it = m_factories.find( name ); - if( it == m_factories.end() ) - return NULL; - return it->second->create( ReporterConfig( config ) ); - } - - void registerReporter( std::string const& name, IReporterFactory* factory ) { - m_factories.insert( std::make_pair( name, factory ) ); - } - - FactoryMap const& getFactories() const { - return m_factories; - } - - private: - FactoryMap m_factories; - }; -} - -// #included from: catch_exception_translator_registry.hpp -#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED - -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry() { - deleteAll( m_translators ); - } - - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( translator ); - } - - virtual std::string translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - throw; - } - @catch (NSException *exception) { - return Catch::toString( [exception description] ); - } -#else - throw; -#endif - } - catch( TestFailureException& ) { - throw; - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return tryTranslators( m_translators.begin() ); - } - } - - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } - } - - private: - std::vector m_translators; - }; -} - -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, public IMutableRegistryHub { - - RegistryHub( RegistryHub const& ); - void operator=( RegistryHub const& ); - - public: // IRegistryHub - RegistryHub() { - } - virtual IReporterRegistry const& getReporterRegistry() const { - return m_reporterRegistry; - } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { - return m_testCaseRegistry; - } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { - return m_exceptionTranslatorRegistry; - } - - public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { - m_reporterRegistry.registerReporter( name, factory ); - } - virtual void registerTest( TestCase const& testInfo ) { - m_testCaseRegistry.registerTest( testInfo ); - } - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - }; - - // Single, global, instance - inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = NULL; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch - -// #included from: catch_notimplemented_exception.hpp -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED - -#include - -namespace Catch { - - NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) - : m_lineInfo( lineInfo ) { - std::ostringstream oss; - oss << lineInfo << ": function "; - oss << "not implemented"; - m_what = oss.str(); - } - - const char* NotImplementedException::what() const CATCH_NOEXCEPT { - return m_what.c_str(); - } - -} // end namespace Catch - -// #included from: catch_context_impl.hpp -#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED - -// #included from: catch_stream.hpp -#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED - -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - -#include -#include -#include - -namespace Catch { - - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() CATCH_NOEXCEPT { - sync(); - } - - private: - int overflow( int c ) { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) - {} - - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) - {} - - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } - } - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } -#endif -} - -namespace Catch { - - class Context : public IMutableContext { - - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} - Context( Context const& ); - void operator=( Context const& ); - - public: // IContext - virtual IResultCapture* getResultCapture() { - return m_resultCapture; - } - virtual IRunner* getRunner() { - return m_runner; - } - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { - return getGeneratorsForCurrentTest() - .getGeneratorInfo( fileInfo, totalSize ) - .getCurrentIndex(); - } - virtual bool advanceGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - return generators && generators->moveNext(); - } - - virtual Ptr getConfig() const { - return m_config; - } - - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) { - m_runner = runner; - } - virtual void setConfig( Ptr const& config ) { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IGeneratorsForTest* findGeneratorsForCurrentTest() { - std::string testName = getResultCapture()->getCurrentTestName(); - - std::map::const_iterator it = - m_generatorsByTestName.find( testName ); - return it != m_generatorsByTestName.end() - ? it->second - : NULL; - } - - IGeneratorsForTest& getGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - if( !generators ) { - std::string testName = getResultCapture()->getCurrentTestName(); - generators = createGeneratorsForTest(); - m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); - } - return *generators; - } - - private: - Ptr m_config; - IRunner* m_runner; - IResultCapture* m_resultCapture; - std::map m_generatorsByTestName; - }; - - namespace { - Context* currentContext = NULL; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } - - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - - void cleanUpContext() { - delete currentContext; - currentContext = NULL; - } -} - -// #included from: catch_console_colour_impl.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED - -namespace Catch { - namespace { - - struct IColourImpl { - virtual ~IColourImpl() {} - virtual void use( Colour::Code _colourCode ) = 0; - }; - - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; - - } // anon namespace -} // namespace Catch - -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif -#endif - -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -namespace Catch { -namespace { - - class Win32ColourImpl : public IColourImpl { - public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; - } - - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); - - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } - - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); - } - HANDLE stdoutHandle; - WORD originalAttributes; - }; - - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; - return &s_instance; - } - -} // end anon namespace -} // end namespace Catch - -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// - -#include - -namespace Catch { -namespace { - - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0:34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); - - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); - - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; - } - - private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } - }; - - IColourImpl* platformColourInstance() { - Ptr config = getCurrentContext().getConfig(); - return (config && config->forceColour()) || isatty(STDOUT_FILENO) - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#else // not Windows or ANSI /////////////////////////////////////////////// - -namespace Catch { - - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } - -} // end namespace Catch - -#endif // Windows/ ANSI/ None - -namespace Catch { - - Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } - Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } - Colour::~Colour(){ if( !m_moved ) use( None ); } - - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = isDebuggerActive() - ? NoColourImpl::instance() - : platformColourInstance(); - impl->use( _colourCode ); - } - -} // end namespace Catch - -// #included from: catch_generators_impl.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - struct GeneratorInfo : IGeneratorInfo { - - GeneratorInfo( std::size_t size ) - : m_size( size ), - m_currentIndex( 0 ) - {} - - bool moveNext() { - if( ++m_currentIndex == m_size ) { - m_currentIndex = 0; - return false; - } - return true; - } - - std::size_t getCurrentIndex() const { - return m_currentIndex; - } - - std::size_t m_size; - std::size_t m_currentIndex; - }; - - /////////////////////////////////////////////////////////////////////////// - - class GeneratorsForTest : public IGeneratorsForTest { - - public: - ~GeneratorsForTest() { - deleteAll( m_generatorsInOrder ); - } - - IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { - std::map::const_iterator it = m_generatorsByName.find( fileInfo ); - if( it == m_generatorsByName.end() ) { - IGeneratorInfo* info = new GeneratorInfo( size ); - m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); - m_generatorsInOrder.push_back( info ); - return *info; - } - return *it->second; - } - - bool moveNext() { - std::vector::const_iterator it = m_generatorsInOrder.begin(); - std::vector::const_iterator itEnd = m_generatorsInOrder.end(); - for(; it != itEnd; ++it ) { - if( (*it)->moveNext() ) - return true; - } - return false; - } - - private: - std::map m_generatorsByName; - std::vector m_generatorsInOrder; - }; - - IGeneratorsForTest* createGeneratorsForTest() - { - return new GeneratorsForTest(); - } - -} // end namespace Catch - -// #included from: catch_assertionresult.hpp -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED - -namespace Catch { - - AssertionInfo::AssertionInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ) - {} - - AssertionResult::AssertionResult() {} - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - AssertionResult::~AssertionResult() {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return !m_info.capturedExpression.empty(); - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!" + m_info.capturedExpression; - else - return m_info.capturedExpression; - } - std::string AssertionResult::getExpressionInMacro() const { - if( m_info.macroName.empty() ) - return m_info.capturedExpression; - else - return m_info.macroName + "( " + m_info.capturedExpression + " )"; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructedExpression; - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch - -// #included from: catch_test_case_info.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED - -namespace Catch { - - inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, "." ) || - tag == "hide" || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else - return TestCaseInfo::None; - } - inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); - } - inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - if( isReservedTag( tag ) ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "Tag name [" << tag << "] not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n"; - } - { - Colour colourGuard( Colour::FileName ); - Catch::cerr() << _lineInfo << std::endl; - } - exit(1); - } - } - - TestCase makeTestCase( ITestCase* _testCase, - std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden( startsWith( _name, "./" ) ); // Legacy support - - // Parse out tags - std::set tags; - std::string desc, tag; - bool inTag = false; - for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { - char c = _descOrTags[i]; - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( prop == TestCaseInfo::IsHidden ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.insert( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.insert( "hide" ); - tags.insert( "." ); - } - - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - tags( _tags ), - lineInfo( _lineInfo ), - properties( None ) - { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); - } - - TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) - : name( other.name ), - className( other.className ), - description( other.description ), - tags( other.tags ), - lcaseTags( other.lcaseTags ), - tagsAsString( other.tagsAsString ), - lineInfo( other.lineInfo ), - properties( other.properties ) - {} - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} - - TestCase::TestCase( TestCase const& other ) - : TestCaseInfo( other ), - test( other.test ) - {} - - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::swap( TestCase& other ) { - test.swap( other.test ); - name.swap( other.name ); - className.swap( other.className ); - description.swap( other.description ); - tags.swap( other.tags ); - lcaseTags.swap( other.lcaseTags ); - tagsAsString.swap( other.tagsAsString ); - std::swap( TestCaseInfo::properties, static_cast( other ).properties ); - std::swap( lineInfo, other.lineInfo ); - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - TestCase& TestCase::operator = ( TestCase const& other ) { - TestCase temp( other ); - swap( temp ); - return *this; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } - -} // end namespace Catch - -// #included from: catch_version.hpp -#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - std::string const& _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << "." - << version.minorVersion << "." - << version.patchNumber; - - if( !version.branchName.empty() ) { - os << "-" << version.branchName - << "." << version.buildNumber; - } - return os; - } - - Version libraryVersion( 1, 2, 1, "", 0 ); - -} - -// #included from: catch_message.hpp -#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED - -namespace Catch { - - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - ScopedMessage::ScopedMessage( ScopedMessage const& other ) - : m_info( other.m_info ) - {} - - ScopedMessage::~ScopedMessage() { - getResultCapture().popScopedMessage( m_info ); - } - -} // end namespace Catch - -// #included from: catch_legacy_reporter_adapter.hpp -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED - -// #included from: catch_legacy_reporter_adapter.h -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED - -namespace Catch -{ - // Deprecated - struct IReporter : IShared { - virtual ~IReporter(); - - virtual bool shouldRedirectStdout() const = 0; - - virtual void StartTesting() = 0; - virtual void EndTesting( Totals const& totals ) = 0; - virtual void StartGroup( std::string const& groupName ) = 0; - virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; - virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; - virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; - virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; - virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; - virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; - virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; - virtual void Aborted() = 0; - virtual void Result( AssertionResult const& result ) = 0; - }; - - class LegacyReporterAdapter : public SharedImpl - { - public: - LegacyReporterAdapter( Ptr const& legacyReporter ); - virtual ~LegacyReporterAdapter(); - - virtual ReporterPreferences getPreferences() const; - virtual void noMatchingTestCases( std::string const& ); - virtual void testRunStarting( TestRunInfo const& ); - virtual void testGroupStarting( GroupInfo const& groupInfo ); - virtual void testCaseStarting( TestCaseInfo const& testInfo ); - virtual void sectionStarting( SectionInfo const& sectionInfo ); - virtual void assertionStarting( AssertionInfo const& ); - virtual bool assertionEnded( AssertionStats const& assertionStats ); - virtual void sectionEnded( SectionStats const& sectionStats ); - virtual void testCaseEnded( TestCaseStats const& testCaseStats ); - virtual void testGroupEnded( TestGroupStats const& testGroupStats ); - virtual void testRunEnded( TestRunStats const& testRunStats ); - virtual void skipTest( TestCaseInfo const& ); - - private: - Ptr m_legacyReporter; - }; -} - -namespace Catch -{ - LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) - : m_legacyReporter( legacyReporter ) - {} - LegacyReporterAdapter::~LegacyReporterAdapter() {} - - ReporterPreferences LegacyReporterAdapter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); - return prefs; - } - - void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} - void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { - m_legacyReporter->StartTesting(); - } - void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { - m_legacyReporter->StartGroup( groupInfo.name ); - } - void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { - m_legacyReporter->StartTestCase( testInfo ); - } - void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { - m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); - } - void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { - // Not on legacy interface - } - - bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); - rb << it->message; - rb.setResultType( ResultWas::Info ); - AssertionResult result = rb.build(); - m_legacyReporter->Result( result ); - } - } - } - m_legacyReporter->Result( assertionStats.assertionResult ); - return true; - } - void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { - if( sectionStats.missingAssertions ) - m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); - m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); - } - void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { - m_legacyReporter->EndTestCase - ( testCaseStats.testInfo, - testCaseStats.totals, - testCaseStats.stdOut, - testCaseStats.stdErr ); - } - void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { - if( testGroupStats.aborting ) - m_legacyReporter->Aborted(); - m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); - } - void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { - m_legacyReporter->EndTesting( testRunStats.totals ); - } - void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { - } -} - -// #included from: catch_timer.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc++11-long-long" -#endif - -#ifdef CATCH_PLATFORM_WINDOWS -#include -#else -#include -#endif - -namespace Catch { - - namespace { -#ifdef CATCH_PLATFORM_WINDOWS - uint64_t getCurrentTicks() { - static uint64_t hz=0, hzo=0; - if (!hz) { - QueryPerformanceFrequency( reinterpret_cast( &hz ) ); - QueryPerformanceCounter( reinterpret_cast( &hzo ) ); - } - uint64_t t; - QueryPerformanceCounter( reinterpret_cast( &t ) ); - return ((t-hzo)*1000000)/hz; - } -#else - uint64_t getCurrentTicks() { - timeval t; - gettimeofday(&t,NULL); - return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); - } -#endif - } - - void Timer::start() { - m_ticks = getCurrentTicks(); - } - unsigned int Timer::getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - unsigned int Timer::getElapsedMilliseconds() const { - return static_cast(getElapsedMicroseconds()/1000); - } - double Timer::getElapsedSeconds() const { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -// #included from: catch_common.hpp -#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << " " << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << "s"; - return os; - } - - SourceLineInfo::SourceLineInfo() : line( 0 ){} - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) - : file( _file ), - line( _line ) - {} - SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) - : file( other.file ), - line( other.line ) - {} - bool SourceLineInfo::empty() const { - return file.empty(); - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { - return line == other.line && file == other.file; - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { - return line < other.line || ( line == other.line && file < other.file ); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << "(" << info.line << ")"; -#else - os << info.file << ":" << info.line; -#endif - return os; - } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { - std::ostringstream oss; - oss << locationInfo << ": Internal Catch error: '" << message << "'"; - if( alwaysTrue() ) - throw std::logic_error( oss.str() ); - } -} - -// #included from: catch_section.hpp -#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED - -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - - Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); - } - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - -} // end namespace Catch - -// #included from: catch_debugger.hpp -#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED - -#include - -#ifdef CATCH_PLATFORM_MAC - - #include - #include - #include - #include - #include - - namespace Catch{ - - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html - - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ - - int mib[4]; - struct kinfo_proc info; - size_t size; - - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - - info.kp_proc.p_flag = 0; - - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - // Call sysctl. - - size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; - return false; - } - - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch - -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#else - namespace Catch { - inline bool isDebuggerActive() { return false; } - } -#endif // Platform - -#ifdef CATCH_PLATFORM_WINDOWS - extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } -#else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } -#endif // Platform - -// #included from: catch_tostring.hpp -#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED - -namespace Catch { - -namespace Detail { - - std::string unprintableString = "{?}"; - - namespace { - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } - - std::string rawMemoryToString( const void *object, std::size_t size ) - { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); - } -} - -std::string toString( std::string const& value ) { - std::string s = value; - if( getCurrentContext().getConfig()->showInvisibles() ) { - for(size_t i = 0; i < s.size(); ++i ) { - std::string subs; - switch( s[i] ) { - case '\n': subs = "\\n"; break; - case '\t': subs = "\\t"; break; - default: break; - } - if( !subs.empty() ) { - s = s.substr( 0, i ) + subs + s.substr( i+1 ); - ++i; - } - } - } - return "\"" + s + "\""; -} -std::string toString( std::wstring const& value ) { - - std::string s; - s.reserve( value.size() ); - for(size_t i = 0; i < value.size(); ++i ) - s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; - return Catch::toString( s ); -} - -std::string toString( const char* const value ) { - return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); -} - -std::string toString( char* const value ) { - return Catch::toString( static_cast( value ) ); -} - -std::string toString( const wchar_t* const value ) -{ - return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); -} - -std::string toString( wchar_t* const value ) -{ - return Catch::toString( static_cast( value ) ); -} - -std::string toString( int value ) { - std::ostringstream oss; - oss << value; - if( value >= 255 ) - oss << " (0x" << std::hex << value << ")"; - return oss.str(); -} - -std::string toString( unsigned long value ) { - std::ostringstream oss; - oss << value; - if( value >= 255 ) - oss << " (0x" << std::hex << value << ")"; - return oss.str(); -} - -std::string toString( unsigned int value ) { - return Catch::toString( static_cast( value ) ); -} - -template -std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} - -std::string toString( const double value ) { - return fpToString( value, 10 ); -} -std::string toString( const float value ) { - return fpToString( value, 5 ) + "f"; -} - -std::string toString( bool value ) { - return value ? "true" : "false"; -} - -std::string toString( char value ) { - return value < ' ' - ? toString( static_cast( value ) ) - : Detail::makeString( value ); -} - -std::string toString( signed char value ) { - return toString( static_cast( value ) ); -} - -std::string toString( unsigned char value ) { - return toString( static_cast( value ) ); -} - -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ) { - return "nullptr"; -} -#endif - -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); - } - std::string toString( NSObject* const& nsObject ) { - return toString( [nsObject description] ); - } -#endif - -} // end namespace Catch - -// #included from: catch_result_builder.hpp -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED - -namespace Catch { - - ResultBuilder::ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), - m_shouldDebugBreak( false ), - m_shouldThrow( false ) - {} - - ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { - m_data.resultType = result; - return *this; - } - ResultBuilder& ResultBuilder::setResultType( bool result ) { - m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; - return *this; - } - ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { - m_exprComponents.lhs = lhs; - return *this; - } - ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { - m_exprComponents.rhs = rhs; - return *this; - } - ResultBuilder& ResultBuilder::setOp( std::string const& op ) { - m_exprComponents.op = op; - return *this; - } - - void ResultBuilder::endExpression() { - m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); - captureExpression(); - } - - void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - m_stream.oss << Catch::translateActiveException(); - captureResult( ResultWas::ThrewException ); - } - - void ResultBuilder::captureResult( ResultWas::OfType resultType ) { - setResultType( resultType ); - captureExpression(); - } - - void ResultBuilder::captureExpression() { - AssertionResult result = build(); - getResultCapture().assertionEnded( result ); - - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) - m_shouldThrow = true; - } - } - void ResultBuilder::react() { - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } - - bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } - bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } - - AssertionResult ResultBuilder::build() const - { - assert( m_data.resultType != ResultWas::Unknown ); - - AssertionResultData data = m_data; - - // Flip bool results if testFalse is set - if( m_exprComponents.testFalse ) { - if( data.resultType == ResultWas::Ok ) - data.resultType = ResultWas::ExpressionFailed; - else if( data.resultType == ResultWas::ExpressionFailed ) - data.resultType = ResultWas::Ok; - } - - data.message = m_stream.oss.str(); - data.reconstructedExpression = reconstructExpression(); - if( m_exprComponents.testFalse ) { - if( m_exprComponents.op == "" ) - data.reconstructedExpression = "!" + data.reconstructedExpression; - else - data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; - } - return AssertionResult( m_assertionInfo, data ); - } - std::string ResultBuilder::reconstructExpression() const { - if( m_exprComponents.op == "" ) - return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; - else if( m_exprComponents.op == "matches" ) - return m_exprComponents.lhs + " " + m_exprComponents.rhs; - else if( m_exprComponents.op != "!" ) { - if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && - m_exprComponents.lhs.find("\n") == std::string::npos && - m_exprComponents.rhs.find("\n") == std::string::npos ) - return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; - else - return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; - } - else - return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; - } - -} // end namespace Catch - -// #included from: catch_tag_alias_registry.hpp -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED - -// #included from: catch_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED - -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - virtual ~TagAliasRegistry(); - virtual Option find( std::string const& alias ) const; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; - void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - static TagAliasRegistry& get(); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -#include -#include - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - Option TagAliasRegistry::find( std::string const& alias ) const { - std::map::const_iterator it = m_registry.find( alias ); - if( it != m_registry.end() ) - return it->second; - else - return Option(); - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); - it != itEnd; - ++it ) { - std::size_t pos = expandedTestSpec.find( it->first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - it->second.tag + - expandedTestSpec.substr( pos + it->first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - - if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { - std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; - throw std::domain_error( oss.str().c_str() ); - } - if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { - std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" already registered.\n" - << "\tFirst seen at " << find(alias)->lineInfo << "\n" - << "\tRedefined at " << lineInfo; - throw std::domain_error( oss.str().c_str() ); - } - } - - TagAliasRegistry& TagAliasRegistry::get() { - static TagAliasRegistry instance; - return instance; - - } - - ITagAliasRegistry::~ITagAliasRegistry() {} - ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } - - RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - try { - TagAliasRegistry::get().add( alias, tag, lineInfo ); - } - catch( std::exception& ex ) { - Colour colourGuard( Colour::Red ); - Catch::cerr() << ex.what() << std::endl; - exit(1); - } - } - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_xml.hpp -#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED - -// #included from: catch_reporter_bases.hpp -#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED - -#include - -namespace Catch { - - struct StreamingReporterBase : SharedImpl { - - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - {} - - virtual ~StreamingReporterBase(); - - virtual void noMatchingTestCases( std::string const& ) {} - - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { - currentTestRunInfo = _testRunInfo; - } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { - currentGroupInfo = _groupInfo; - } - - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { - currentTestCaseInfo = _testInfo; - } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { - m_sectionStack.push_back( _sectionInfo ); - } - - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { - currentTestCaseInfo.reset(); - } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { - currentGroupInfo.reset(); - } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - virtual void skipTest( TestCaseInfo const& ) { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - Ptr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - }; - - struct CumulativeReporterBase : SharedImpl { - template - struct Node : SharedImpl<> { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - typedef std::vector > ChildNodes; - T value; - ChildNodes children; - }; - struct SectionNode : SharedImpl<> { - explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} - virtual ~SectionNode(); - - bool operator == ( SectionNode const& other ) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == ( Ptr const& other ) const { - return operator==( *other ); - } - - SectionStats stats; - typedef std::vector > ChildSections; - typedef std::vector Assertions; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; - - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() ( Ptr const& node ) const { - return node->stats.sectionInfo.lineInfo == m_other.lineInfo; - } - private: - void operator=( BySectionInfo const& ); - SectionInfo const& m_other; - }; - - typedef Node TestCaseNode; - typedef Node TestGroupNode; - typedef Node TestRunNode; - - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - {} - ~CumulativeReporterBase(); - - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} - - virtual void testCaseStarting( TestCaseInfo const& ) {} - - virtual void sectionStarting( SectionInfo const& sectionInfo ) { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - Ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = new SectionNode( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - SectionNode::ChildSections::const_iterator it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = new SectionNode( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = node; - } - - virtual void assertionStarting( AssertionInfo const& ) {} - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - assert( !m_sectionStack.empty() ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back( assertionStats ); - return true; - } - virtual void sectionEnded( SectionStats const& sectionStats ) { - assert( !m_sectionStack.empty() ); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - Ptr node = new TestCaseNode( testCaseStats ); - assert( m_sectionStack.size() == 0 ); - node->children.push_back( m_rootSection ); - m_testCases.push_back( node ); - m_rootSection.reset(); - - assert( m_deepestSection ); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - Ptr node = new TestGroupNode( testGroupStats ); - node->children.swap( m_testCases ); - m_testGroups.push_back( node ); - } - virtual void testRunEnded( TestRunStats const& testRunStats ) { - Ptr node = new TestRunNode( testRunStats ); - node->children.swap( m_testGroups ); - m_testRuns.push_back( node ); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; - - virtual void skipTest( TestCaseInfo const& ) {} - - Ptr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector > > m_sections; - std::vector > m_testCases; - std::vector > m_testGroups; - - std::vector > m_testRuns; - - Ptr m_rootSection; - Ptr m_deepestSection; - std::vector > m_sectionStack; - - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } - -} // end namespace Catch - -// #included from: ../internal/catch_reporter_registrars.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED - -namespace Catch { - - template - class LegacyReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new LegacyReporterAdapter( new T( config ) ); - } - - virtual std::string getDescription() const { - return T::getDescription(); - } - }; - - public: - - LegacyReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } - }; - - template - class ReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - - // *** Please Note ***: - // - If you end up here looking at a compiler error because it's trying to register - // your custom reporter class be aware that the native reporter interface has changed - // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via - // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. - // However please consider updating to the new interface as the old one is now - // deprecated and will probably be removed quite soon! - // Please contact me via github if you have any questions at all about this. - // In fact, ideally, please contact me anyway to let me know you've hit this - as I have - // no idea who is actually using custom reporters at all (possibly no-one!). - // The new interface is designed to minimise exposure to interface changes in the future. - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); - } - - virtual std::string getDescription() const { - return T::getDescription(); - } - }; - - public: - - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); - } - }; -} - -#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ - namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } -#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } - -// #included from: ../internal/catch_xmlwriter.hpp -#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - ScopedElement( ScopedElement const& other ) - : m_writer( other.m_writer ){ - other.m_writer = NULL; - } - - ~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - ScopedElement& writeText( std::string const& text, bool indent = true ) { - m_writer->writeText( text, indent ); - return *this; - } - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer; - }; - - XmlWriter() - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( &Catch::cout() ) - {} - - XmlWriter( std::ostream& os ) - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( &os ) - {} - - ~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - stream() << m_indent << "<" << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - ScopedElement scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - stream() << "/>\n"; - m_tagIsOpen = false; - } - else { - stream() << m_indent << "\n"; - } - m_tags.pop_back(); - return *this; - } - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } - return *this; - } - - XmlWriter& writeAttribute( std::string const& name, bool attribute ) { - stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; - return *this; - } - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; - } - - XmlWriter& writeText( std::string const& text, bool indent = true ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - stream() << m_indent; - writeEncodedText( text ); - m_needsNewline = true; - } - return *this; - } - - XmlWriter& writeComment( std::string const& text ) { - ensureTagClosed(); - stream() << m_indent << ""; - m_needsNewline = true; - return *this; - } - - XmlWriter& writeBlankLine() { - ensureTagClosed(); - stream() << "\n"; - return *this; - } - - void setStream( std::ostream& os ) { - m_os = &os; - } - - private: - XmlWriter( XmlWriter const& ); - void operator=( XmlWriter const& ); - - std::ostream& stream() { - return *m_os; - } - - void ensureTagClosed() { - if( m_tagIsOpen ) { - stream() << ">\n"; - m_tagIsOpen = false; - } - } - - void newlineIfNecessary() { - if( m_needsNewline ) { - stream() << "\n"; - m_needsNewline = false; - } - } - - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - - bool m_tagIsOpen; - bool m_needsNewline; - std::vector m_tags; - std::string m_indent; - std::ostream* m_os; - }; - -} -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_sectionDepth( 0 ) - {} - - virtual ~XmlReporter(); - - static std::string getDescription() { - return "Reports test results as an XML document"; - } - - public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& s ) { - StreamingReporterBase::noMatchingTestCases( s ); - } - - virtual void testRunStarting( TestRunInfo const& testInfo ) { - StreamingReporterBase::testRunStarting( testInfo ); - m_xml.setStream( stream ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - } - - virtual void sectionStarting( SectionInfo const& sectionInfo ) { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - } - } - - virtual void assertionStarting( AssertionInfo const& ) { } - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - const AssertionResult& assertionResult = assertionStats.assertionResult; - - // Print any info messages in tags. - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( it->message ); - } else if ( it->type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( it->message ); - } - } - } - - // Drop out if result was successful but we're not printing them. - if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) - return true; - - // Print the expression if there is one. - if( assertionResult.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", assertionResult.succeeded() ) - .writeAttribute( "type", assertionResult.getTestMacroName() ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ); - - m_xml.scopedElement( "Original" ) - .writeText( assertionResult.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( assertionResult.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( assertionResult.getResultType() ) { - case ResultWas::ThrewException: - m_xml.scopedElement( "Exception" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( assertionResult.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.scopedElement( "Failure" ) - .writeText( assertionResult.getMessage() ); - break; - default: - break; - } - - if( assertionResult.hasExpression() ) - m_xml.endElement(); - - return true; - } - - virtual void sectionEnded( SectionStats const& sectionStats ) { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); - } - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - m_xml.endElement(); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - virtual void testRunEnded( TestRunStats const& testRunStats ) { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_junit.hpp -#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED - -#include - -namespace Catch { - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - {} - - ~JunitReporter(); - - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} - - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - virtual void testRunEndedCumulative() { - xml.endElement(); - } - - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", "tbd" ); // !TBD - - // Write test cases - for( TestGroupNode::ChildNodes::const_iterator - it = groupNode.children.begin(), itEnd = groupNode.children.end(); - it != itEnd; - ++it ) - writeTestCase( **it ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } - - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - if( rootSection.childSections.empty() ) - className = "global"; - } - writeSection( className, "", rootSection ); - } - - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + "/" + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( SectionNode::ChildSections::const_iterator - it = sectionNode.childSections.begin(), - itEnd = sectionNode.childSections.end(); - it != itEnd; - ++it ) - if( className.empty() ) - writeSection( name, "", **it ); - else - writeSection( className, name, **it ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( SectionNode::Assertions::const_iterator - it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); - it != itEnd; - ++it ) - writeAssertion( *it ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << "\n"; - for( std::vector::const_iterator - it = stats.infoMessages.begin(), - itEnd = stats.infoMessages.end(); - it != itEnd; - ++it ) - if( it->type == ResultWas::Info ) - oss << it->message << "\n"; - - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } - } - - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_console.hpp -#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED - -namespace Catch { - - struct ConsoleReporter : StreamingReporterBase { - ConsoleReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_headerPrinted( false ) - {} - - virtual ~ConsoleReporter(); - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << "'" << std::endl; - } - - virtual void assertionStarting( AssertionInfo const& ) { - } - - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - lazyPrint(); - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - stream << std::endl; - return true; - } - - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - virtual void sectionEnded( SectionStats const& _sectionStats ) { - if( _sectionStats.missingAssertions ) { - lazyPrint(); - Colour colour( Colour::ResultError ); - if( m_sectionStack.size() > 1 ) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if( m_headerPrinted ) { - if( m_config->showDurations() == ShowDurations::Always ) - stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; - m_headerPrinted = false; - } - else { - if( m_config->showDurations() == ShowDurations::Always ) - stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; - } - StreamingReporterBase::sectionEnded( _sectionStats ); - } - - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; - } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << "\n" << std::endl; - } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - private: - - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ), - stats( _stats ), - result( _stats.assertionResult ), - colour( Colour::None ), - message( result.getMessage() ), - messages( _stats.infoMessages ), - printInfoMessages( _printInfoMessages ) - { - switch( result.getResultType() ) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } - else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with message"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if( _stats.infoMessages.size() == 1 ) - messageLabel = "explicitly with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } - - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << "\n"; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } - else { - stream << "\n"; - } - printMessage(); - } - - private: - void printResultType() const { - if( !passOrFail.empty() ) { - Colour colourGuard( colour ); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if( result.hasExpression() ) { - Colour colourGuard( Colour::OriginalExpression ); - stream << " "; - stream << result.getExpressionInMacro(); - stream << "\n"; - } - } - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - stream << "with expansion:\n"; - Colour colourGuard( Colour::ReconstructedExpression ); - stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; - } - } - void printMessage() const { - if( !messageLabel.empty() ) - stream << messageLabel << ":" << "\n"; - for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); - it != itEnd; - ++it ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || it->type != ResultWas::Info ) - stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; - } - } - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; - }; - - void lazyPrint() { - - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); - - if( !m_headerPrinted ) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } - } - void lazyPrintRunInfo() { - stream << "\n" << getLineOfChars<'~'>() << "\n"; - Colour colour( Colour::SecondaryText ); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion << " host application.\n" - << "Run with -? for options\n\n"; - - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - - currentTestRunInfo.used = true; - } - void lazyPrintGroupInfo() { - if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { - printClosedHeader( "Group: " + currentGroupInfo->name ); - currentGroupInfo.used = true; - } - } - void printTestCaseAndSectionHeader() { - assert( !m_sectionStack.empty() ); - printOpenHeader( currentTestCaseInfo->name ); - - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); - - std::vector::const_iterator - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } - - SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; - - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << "\n"; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << "\n"; - } - stream << getLineOfChars<'.'>() << "\n" << std::endl; - } - - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << "\n"; - } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << "\n"; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } - } - - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { - std::size_t i = _string.find( ": " ); - if( i != std::string::npos ) - i+=2; - else - i = 0; - stream << Text( _string, TextAttributes() - .setIndent( indent+i) - .setInitialIndent( indent ) ) << "\n"; - } - - struct SummaryColumn { - - SummaryColumn( std::string const& _label, Colour::Code _colour ) - : label( _label ), - colour( _colour ) - {} - SummaryColumn addRow( std::size_t count ) { - std::ostringstream oss; - oss << count; - std::string row = oss.str(); - for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { - while( it->size() < row.size() ) - *it = " " + *it; - while( it->size() > row.size() ) - row = " " + row; - } - rows.push_back( row ); - return *this; - } - - std::string label; - Colour::Code colour; - std::vector rows; - - }; - - void printTotals( Totals const& totals ) { - if( totals.testCases.total() == 0 ) { - stream << Colour( Colour::Warning ) << "No tests ran\n"; - } - else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { - stream << Colour( Colour::ResultSuccess ) << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ")" - << "\n"; - } - else { - - std::vector columns; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); - - printSummaryRow( "test cases", columns, 0 ); - printSummaryRow( "assertions", columns, 1 ); - } - } - void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { - std::string value = it->rows[row]; - if( it->label.empty() ) { - stream << label << ": "; - if( value != "0" ) - stream << value; - else - stream << Colour( Colour::Warning ) << "- none -"; - } - else if( value != "0" ) { - stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( it->colour ) - << value << " " << it->label; - } - } - stream << "\n"; - } - - static std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; - } - static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; - } - - void printTotalsDivider( Totals const& totals ) { - if( totals.testCases.total() > 0 ) { - std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); - std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); - std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); - while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )++; - while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )--; - - stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); - stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); - if( totals.testCases.allPassed() ) - stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); - else - stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); - } - else { - stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); - } - stream << "\n"; - } - void printSummaryDivider() { - stream << getLineOfChars<'-'>() << "\n"; - } - - private: - bool m_headerPrinted; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) - -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_compact.hpp -#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED - -namespace Catch { - - struct CompactReporter : StreamingReporterBase { - - CompactReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} - - virtual ~CompactReporter(); - - static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } - - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << "'" << std::endl; - } - - virtual void assertionStarting( AssertionInfo const& ) { - } - - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - - stream << std::endl; - return true; - } - - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( _testRunStats.totals ); - stream << "\n" << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - private: - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , stats( _stats ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } - - private: - // Colour::LightGrey - - static Colour::Code dimColour() { return Colour::FileName; } - -#ifdef CATCH_PLATFORM_MAC - static const char* failedString() { return "FAILED"; } - static const char* passedString() { return "PASSED"; } -#else - static const char* failedString() { return "failed"; } - static const char* passedString() { return "passed"; } -#endif - - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ":"; - } - - void printResultType( Colour::Code colour, std::string passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << " " << passOrFail; - } - stream << ":"; - } - } - - void printIssue( std::string issue ) const { - stream << " " << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ";"; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << " " << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << "'"; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ":"; - } - - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << "'"; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - std::string bothOrAll( std::size_t count ) const { - return count == 1 ? "" : count == 2 ? "both " : "all " ; - } - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : ""; - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << "."; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; - } - } - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) - -} // end namespace Catch - -namespace Catch { - NonCopyable::~NonCopyable() {} - IShared::~IShared() {} - StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} - IContext::~IContext() {} - IResultCapture::~IResultCapture() {} - ITestCase::~ITestCase() {} - ITestCaseRegistry::~ITestCaseRegistry() {} - IRegistryHub::~IRegistryHub() {} - IMutableRegistryHub::~IMutableRegistryHub() {} - IExceptionTranslator::~IExceptionTranslator() {} - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} - IReporter::~IReporter() {} - IReporterFactory::~IReporterFactory() {} - IReporterRegistry::~IReporterRegistry() {} - IStreamingReporter::~IStreamingReporter() {} - AssertionStats::~AssertionStats() {} - SectionStats::~SectionStats() {} - TestCaseStats::~TestCaseStats() {} - TestGroupStats::~TestGroupStats() {} - TestRunStats::~TestRunStats() {} - CumulativeReporterBase::SectionNode::~SectionNode() {} - CumulativeReporterBase::~CumulativeReporterBase() {} - - StreamingReporterBase::~StreamingReporterBase() {} - ConsoleReporter::~ConsoleReporter() {} - CompactReporter::~CompactReporter() {} - IRunner::~IRunner() {} - IMutableContext::~IMutableContext() {} - IConfig::~IConfig() {} - XmlReporter::~XmlReporter() {} - JunitReporter::~JunitReporter() {} - TestRegistry::~TestRegistry() {} - FreeFunctionTestCase::~FreeFunctionTestCase() {} - IGeneratorInfo::~IGeneratorInfo() {} - IGeneratorsForTest::~IGeneratorsForTest() {} - TestSpec::Pattern::~Pattern() {} - TestSpec::NamePattern::~NamePattern() {} - TestSpec::TagPattern::~TagPattern() {} - TestSpec::ExcludedPattern::~ExcludedPattern() {} - - Matchers::Impl::StdString::Equals::~Equals() {} - Matchers::Impl::StdString::Contains::~Contains() {} - Matchers::Impl::StdString::StartsWith::~StartsWith() {} - Matchers::Impl::StdString::EndsWith::~EndsWith() {} - - void Config::dummy() {} -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif - -#ifdef CATCH_CONFIG_MAIN -// #included from: internal/catch_default_main.hpp -#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED - -#ifndef __OBJC__ - -// Standard C/C++ main entry point -int main (int argc, char * const argv[]) { - return Catch::Session().run( argc, argv ); -} - -#else // __OBJC__ - -// Objective-C entry point -int main (int argc, char * const argv[]) { -#if !CATCH_ARC_ENABLED - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; -#endif - - Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char* const*)argv ); - -#if !CATCH_ARC_ENABLED - [pool drain]; -#endif - - return result; -} - -#endif // __OBJC__ - -#endif - -#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED -# undef CLARA_CONFIG_MAIN -#endif - -////// - -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) - -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) -#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) - -#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) -#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) -#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) -#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) -#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) - -#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) -#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) - -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) - -#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) -#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) -#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) -#else - #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) - #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) -#endif -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) - -// "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS -#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) -#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) - -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) -#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) -#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) - -#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) -#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) -#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) -#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) -#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) - -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) -#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) -#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) - -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) - -#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) -#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) -#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) - #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) -#else - #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) - #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) - #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) - #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) - #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) -#endif -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) - -#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) - -// "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS -#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) -#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) -#endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) - -using Catch::Detail::Approx; - -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - -#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - diff --git a/3rdparty/doctest.h b/3rdparty/doctest.h new file mode 100644 index 00000000..6082d93c --- /dev/null +++ b/3rdparty/doctest.h @@ -0,0 +1,7112 @@ +/* + SPDX-FileCopyrightText: 2016-2023 Viktor Kirilov + + SPDX-License-Identifier: MIT +*/ + +// ====================================================================== lgtm [cpp/missing-header-guard] +// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == +// ====================================================================== +// +// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD +// +// Copyright (c) 2016-2023 Viktor Kirilov +// +// Distributed under the MIT Software License +// See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/MIT +// +// The documentation can be found at the library's page: +// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= +// +// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt +// +// The concept of subcases (sections in Catch) and expression decomposition are from there. +// Some parts of the code are taken directly: +// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> +// - the Approx() helper class for floating point comparison +// - colors in the console +// - breaking into a debugger +// - signal / SEH handling +// - timer +// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) +// +// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= + +#ifndef DOCTEST_LIBRARY_INCLUDED +#define DOCTEST_LIBRARY_INCLUDED + +// ================================================================================================= +// == VERSION ====================================================================================== +// ================================================================================================= + +#define DOCTEST_VERSION_MAJOR 2 +#define DOCTEST_VERSION_MINOR 4 +#define DOCTEST_VERSION_PATCH 11 + +// util we need here +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) + +#define DOCTEST_VERSION_STR \ + DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_PATCH) + +#define DOCTEST_VERSION \ + (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +// ================================================================================================= +// == COMPILER VERSION ============================================================================= +// ================================================================================================= + +// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect + +#ifdef _MSC_VER +#define DOCTEST_CPLUSPLUS _MSVC_LANG +#else +#define DOCTEST_CPLUSPLUS __cplusplus +#endif + +#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) + +// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... +#if defined(_MSC_VER) && defined(_MSC_FULL_VER) +#if _MSC_VER == _MSC_FULL_VER / 10000 +#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) +#else // MSVC +#define DOCTEST_MSVC \ + DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) +#endif // MSVC +#endif // MSVC +#if defined(__clang__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ + !defined(__INTEL_COMPILER) +#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#endif // GCC +#if defined(__INTEL_COMPILER) +#define DOCTEST_ICC DOCTEST_COMPILER(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif // ICC + +#ifndef DOCTEST_MSVC +#define DOCTEST_MSVC 0 +#endif // DOCTEST_MSVC +#ifndef DOCTEST_CLANG +#define DOCTEST_CLANG 0 +#endif // DOCTEST_CLANG +#ifndef DOCTEST_GCC +#define DOCTEST_GCC 0 +#endif // DOCTEST_GCC +#ifndef DOCTEST_ICC +#define DOCTEST_ICC 0 +#endif // DOCTEST_ICC + +// ================================================================================================= +// == COMPILER WARNINGS HELPERS ==================================================================== +// ================================================================================================= + +#if DOCTEST_CLANG && !DOCTEST_ICC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) +#else // DOCTEST_CLANG +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_CLANG + +#if DOCTEST_GCC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") +#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) +#else // DOCTEST_GCC +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#define DOCTEST_GCC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_GCC + +#if DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) +#else // DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_MSVC + +// ================================================================================================= +// == COMPILER WARNINGS ============================================================================ +// ================================================================================================= + +// both the header and the implementation suppress all of these, +// so it only makes sense to aggregate them like so +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") \ + \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") \ + \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + /* these 4 also disabled globally via cmake: */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ + /* common ones */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5264) /* 'variable-name': 'const' variable is not used */ \ + /* static analysis */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */ + +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + DOCTEST_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5262) /* implicit fall-through */ + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP + +// ================================================================================================= +// == FEATURE DETECTION ============================================================================ +// ================================================================================================= + +// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support +// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx +// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html +// MSVC version table: +// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering +// MSVC++ 14.3 (17) _MSC_VER == 1930 (Visual Studio 2022) +// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) +// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + +// Universal Windows Platform support +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_WINDOWS_SEH +#endif // WINAPI_FAMILY +#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +#define DOCTEST_CONFIG_WINDOWS_SEH +#endif // MSVC +#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) +#undef DOCTEST_CONFIG_WINDOWS_SEH +#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH + +#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \ + !defined(__EMSCRIPTEN__) && !defined(__wasi__) +#define DOCTEST_CONFIG_POSIX_SIGNALS +#endif // _WIN32 +#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#undef DOCTEST_CONFIG_POSIX_SIGNALS +#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) \ + || defined(__wasi__) +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // no exceptions +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) +#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#ifdef __wasi__ +#define DOCTEST_CONFIG_NO_MULTITHREADING +#endif + +#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) +#define DOCTEST_CONFIG_IMPLEMENT +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#if defined(_WIN32) || defined(__CYGWIN__) +#if DOCTEST_MSVC +#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) +#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) +#else // MSVC +#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) +#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) +#endif // MSVC +#else // _WIN32 +#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) +#define DOCTEST_SYMBOL_IMPORT +#endif // _WIN32 + +#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#ifdef DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT +#else // DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT +#endif // DOCTEST_CONFIG_IMPLEMENT +#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#define DOCTEST_INTERFACE +#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL + +// needed for extern template instantiations +// see https://github.com/fmtlib/fmt/issues/2228 +#if DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL +#define DOCTEST_INTERFACE_DEF DOCTEST_INTERFACE +#else // DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL DOCTEST_INTERFACE +#define DOCTEST_INTERFACE_DEF +#endif // DOCTEST_MSVC + +#define DOCTEST_EMPTY + +#if DOCTEST_MSVC +#define DOCTEST_NOINLINE __declspec(noinline) +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0) +#define DOCTEST_NOINLINE +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#else +#define DOCTEST_NOINLINE __attribute__((noinline)) +#define DOCTEST_UNUSED __attribute__((unused)) +#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) +#endif + +#ifdef DOCTEST_CONFIG_NO_CONTRADICTING_INLINE +#define DOCTEST_INLINE_NOINLINE inline +#else +#define DOCTEST_INLINE_NOINLINE inline DOCTEST_NOINLINE +#endif + +#ifndef DOCTEST_NORETURN +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NORETURN +#else // DOCTEST_MSVC +#define DOCTEST_NORETURN [[noreturn]] +#endif // DOCTEST_MSVC +#endif // DOCTEST_NORETURN + +#ifndef DOCTEST_NOEXCEPT +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NOEXCEPT +#else // DOCTEST_MSVC +#define DOCTEST_NOEXCEPT noexcept +#endif // DOCTEST_MSVC +#endif // DOCTEST_NOEXCEPT + +#ifndef DOCTEST_CONSTEXPR +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_CONSTEXPR const +#define DOCTEST_CONSTEXPR_FUNC inline +#else // DOCTEST_MSVC +#define DOCTEST_CONSTEXPR constexpr +#define DOCTEST_CONSTEXPR_FUNC constexpr +#endif // DOCTEST_MSVC +#endif // DOCTEST_CONSTEXPR + +#ifndef DOCTEST_NO_SANITIZE_INTEGER +#if DOCTEST_CLANG >= DOCTEST_COMPILER(3, 7, 0) +#define DOCTEST_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer"))) +#else +#define DOCTEST_NO_SANITIZE_INTEGER +#endif +#endif // DOCTEST_NO_SANITIZE_INTEGER + +// ================================================================================================= +// == FEATURE DETECTION END ======================================================================== +// ================================================================================================= + +#define DOCTEST_DECLARE_INTERFACE(name) \ + virtual ~name(); \ + name() = default; \ + name(const name&) = delete; \ + name(name&&) = delete; \ + name& operator=(const name&) = delete; \ + name& operator=(name&&) = delete; + +#define DOCTEST_DEFINE_INTERFACE(name) \ + name::~name() = default; + +// internal macros for string concatenation and anonymous variable name generation +#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 +#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) +#ifdef __COUNTER__ // not standard and may be missing for some compilers +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) +#else // __COUNTER__ +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) +#endif // __COUNTER__ + +#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x& +#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x +#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE + +// not using __APPLE__ because... this is how Catch does it +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +#define DOCTEST_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_IPHONE +#elif defined(_WIN32) +#define DOCTEST_PLATFORM_WINDOWS +#elif defined(__wasi__) +#define DOCTEST_PLATFORM_WASI +#else // DOCTEST_PLATFORM +#define DOCTEST_PLATFORM_LINUX +#endif // DOCTEST_PLATFORM + +namespace doctest { namespace detail { + static DOCTEST_CONSTEXPR int consume(const int*, int) noexcept { return 0; } +}} + +#define DOCTEST_GLOBAL_NO_WARNINGS(var, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ + static const int var = doctest::detail::consume(&var, __VA_ARGS__); \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#ifndef DOCTEST_BREAK_INTO_DEBUGGER +// should probably take a look at https://github.com/scottt/debugbreak +#ifdef DOCTEST_PLATFORM_LINUX +#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) +// Break at the location of the failing check if possible +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT(hicpp-no-assembler) +#else +#include +#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) +#endif +#elif defined(DOCTEST_PLATFORM_MAC) +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT(hicpp-no-assembler) +#elif defined(__ppc__) || defined(__ppc64__) +// https://www.cocoawithlove.com/2008/03/break-into-debugger.html +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n": : : "memory","r0","r3","r4") // NOLINT(hicpp-no-assembler) +#else +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT(hicpp-no-assembler) +#endif +#elif DOCTEST_MSVC +#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() +#elif defined(__MINGW32__) +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() +#else // linux +#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast(0)) +#endif // linux +#endif // DOCTEST_BREAK_INTO_DEBUGGER + +// this is kept here for backwards compatibility since the config option was changed +#ifdef DOCTEST_CONFIG_USE_IOSFWD +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // DOCTEST_CONFIG_USE_IOSFWD + +// for clang - always include ciso646 (which drags some std stuff) because +// we want to check if we are using libc++ with the _LIBCPP_VERSION macro in +// which case we don't want to forward declare stuff from std - for reference: +// https://github.com/doctest/doctest/issues/126 +// https://github.com/doctest/doctest/issues/356 +#if DOCTEST_CLANG +#include +#endif // clang + +#ifdef _LIBCPP_VERSION +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // _LIBCPP_VERSION + +#ifdef DOCTEST_CONFIG_USE_STD_HEADERS +#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#include +#include +#include +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#else // DOCTEST_CONFIG_USE_STD_HEADERS + +// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) + +namespace std { // NOLINT(cert-dcl58-cpp) +typedef decltype(nullptr) nullptr_t; // NOLINT(modernize-use-using) +typedef decltype(sizeof(void*)) size_t; // NOLINT(modernize-use-using) +template +struct char_traits; +template <> +struct char_traits; +template +class basic_ostream; // NOLINT(fuchsia-virtual-inheritance) +typedef basic_ostream> ostream; // NOLINT(modernize-use-using) +template +// NOLINTNEXTLINE +basic_ostream& operator<<(basic_ostream&, const char*); +template +class basic_istream; +typedef basic_istream> istream; // NOLINT(modernize-use-using) +template +class tuple; +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +template +class allocator; +template +class basic_string; +using string = basic_string, allocator>; +#endif // VS 2019 +} // namespace std + +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_USE_STD_HEADERS + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#include +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + +namespace doctest { + +using std::size_t; + +DOCTEST_INTERFACE extern bool is_running_in_test; + +#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE +#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned +#endif + +// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length +// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: +// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) +// - if small - capacity left before going on the heap - using the lowest 5 bits +// - if small - 2 bits are left unused - the second and third highest ones +// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) +// and the "is small" bit remains "0" ("as well as the capacity left") so its OK +// Idea taken from this lecture about the string implementation of facebook/folly - fbstring +// https://www.youtube.com/watch?v=kPR8h4-qZdk +// TODO: +// - optimizations - like not deleting memory unnecessarily in operator= and etc. +// - resize/reserve/clear +// - replace +// - back/front +// - iterator stuff +// - find & friends +// - push_back/pop_back +// - assign/insert/erase +// - relational operators as free functions - taking const char* as one of the params +class DOCTEST_INTERFACE String +{ +public: + using size_type = DOCTEST_CONFIG_STRING_SIZE_TYPE; + +private: + static DOCTEST_CONSTEXPR size_type len = 24; //!OCLINT avoid private static members + static DOCTEST_CONSTEXPR size_type last = len - 1; //!OCLINT avoid private static members + + struct view // len should be more than sizeof(view) - because of the final byte for flags + { + char* ptr; + size_type size; + size_type capacity; + }; + + union + { + char buf[len]; // NOLINT(*-avoid-c-arrays) + view data; + }; + + char* allocate(size_type sz); + + bool isOnStack() const noexcept { return (buf[last] & 128) == 0; } + void setOnHeap() noexcept; + void setLast(size_type in = last) noexcept; + void setSize(size_type sz) noexcept; + + void copy(const String& other); + +public: + static DOCTEST_CONSTEXPR size_type npos = static_cast(-1); + + String() noexcept; + ~String(); + + // cppcheck-suppress noExplicitConstructor + String(const char* in); + String(const char* in, size_type in_size); + + String(std::istream& in, size_type in_size); + + String(const String& other); + String& operator=(const String& other); + + String& operator+=(const String& other); + + String(String&& other) noexcept; + String& operator=(String&& other) noexcept; + + char operator[](size_type i) const; + char& operator[](size_type i); + + // the only functions I'm willing to leave in the interface - available for inlining + const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT + char* c_str() { + if (isOnStack()) { + return reinterpret_cast(buf); + } + return data.ptr; + } + + size_type size() const; + size_type capacity() const; + + String substr(size_type pos, size_type cnt = npos) &&; + String substr(size_type pos, size_type cnt = npos) const &; + + size_type find(char ch, size_type pos = 0) const; + size_type rfind(char ch, size_type pos = npos) const; + + int compare(const char* other, bool no_case = false) const; + int compare(const String& other, bool no_case = false) const; + +friend DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); +}; + +DOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs); + +DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs); + +class DOCTEST_INTERFACE Contains { +public: + explicit Contains(const String& string); + + bool checkWith(const String& other) const; + + String string; +}; + +DOCTEST_INTERFACE String toString(const Contains& in); + +DOCTEST_INTERFACE bool operator==(const String& lhs, const Contains& rhs); +DOCTEST_INTERFACE bool operator==(const Contains& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator!=(const String& lhs, const Contains& rhs); +DOCTEST_INTERFACE bool operator!=(const Contains& lhs, const String& rhs); + +namespace Color { + enum Enum + { + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White + }; + + DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code); +} // namespace Color + +namespace assertType { + enum Enum + { + // macro traits + + is_warn = 1, + is_check = 2 * is_warn, + is_require = 2 * is_check, + + is_normal = 2 * is_require, + is_throws = 2 * is_normal, + is_throws_as = 2 * is_throws, + is_throws_with = 2 * is_throws_as, + is_nothrow = 2 * is_throws_with, + + is_false = 2 * is_nothrow, + is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types + + is_eq = 2 * is_unary, + is_ne = 2 * is_eq, + + is_lt = 2 * is_ne, + is_gt = 2 * is_lt, + + is_ge = 2 * is_gt, + is_le = 2 * is_ge, + + // macro types + + DT_WARN = is_normal | is_warn, + DT_CHECK = is_normal | is_check, + DT_REQUIRE = is_normal | is_require, + + DT_WARN_FALSE = is_normal | is_false | is_warn, + DT_CHECK_FALSE = is_normal | is_false | is_check, + DT_REQUIRE_FALSE = is_normal | is_false | is_require, + + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, + + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, + + DT_WARN_THROWS_WITH = is_throws_with | is_warn, + DT_CHECK_THROWS_WITH = is_throws_with | is_check, + DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, + + DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, + DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, + DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, + + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, + + DT_WARN_EQ = is_normal | is_eq | is_warn, + DT_CHECK_EQ = is_normal | is_eq | is_check, + DT_REQUIRE_EQ = is_normal | is_eq | is_require, + + DT_WARN_NE = is_normal | is_ne | is_warn, + DT_CHECK_NE = is_normal | is_ne | is_check, + DT_REQUIRE_NE = is_normal | is_ne | is_require, + + DT_WARN_GT = is_normal | is_gt | is_warn, + DT_CHECK_GT = is_normal | is_gt | is_check, + DT_REQUIRE_GT = is_normal | is_gt | is_require, + + DT_WARN_LT = is_normal | is_lt | is_warn, + DT_CHECK_LT = is_normal | is_lt | is_check, + DT_REQUIRE_LT = is_normal | is_lt | is_require, + + DT_WARN_GE = is_normal | is_ge | is_warn, + DT_CHECK_GE = is_normal | is_ge | is_check, + DT_REQUIRE_GE = is_normal | is_ge | is_require, + + DT_WARN_LE = is_normal | is_le | is_warn, + DT_CHECK_LE = is_normal | is_le | is_check, + DT_REQUIRE_LE = is_normal | is_le | is_require, + + DT_WARN_UNARY = is_normal | is_unary | is_warn, + DT_CHECK_UNARY = is_normal | is_unary | is_check, + DT_REQUIRE_UNARY = is_normal | is_unary | is_require, + + DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, + }; +} // namespace assertType + +DOCTEST_INTERFACE const char* assertString(assertType::Enum at); +DOCTEST_INTERFACE const char* failureString(assertType::Enum at); +DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); + +struct DOCTEST_INTERFACE TestCaseData +{ + String m_file; // the file in which the test was registered (using String - see #350) + unsigned m_line; // the line where the test was registered + const char* m_name; // name of the test case + const char* m_test_suite; // the test suite in which the test was added + const char* m_description; + bool m_skip; + bool m_no_breaks; + bool m_no_output; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; +}; + +struct DOCTEST_INTERFACE AssertData +{ + // common - for all asserts + const TestCaseData* m_test_case; + assertType::Enum m_at; + const char* m_file; + int m_line; + const char* m_expr; + bool m_failed; + + // exception-related - for all asserts + bool m_threw; + String m_exception; + + // for normal asserts + String m_decomp; + + // for specific exception-related asserts + bool m_threw_as; + const char* m_exception_type; + + class DOCTEST_INTERFACE StringContains { + private: + Contains content; + bool isContains; + + public: + StringContains(const String& str) : content(str), isContains(false) { } + StringContains(Contains cntn) : content(static_cast(cntn)), isContains(true) { } + + bool check(const String& str) { return isContains ? (content == str) : (content.string == str); } + + operator const String&() const { return content.string; } + + const char* c_str() const { return content.string.c_str(); } + } m_exception_string; + + AssertData(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const StringContains& exception_string); +}; + +struct DOCTEST_INTERFACE MessageData +{ + String m_string; + const char* m_file; + int m_line; + assertType::Enum m_severity; +}; + +struct DOCTEST_INTERFACE SubcaseSignature +{ + String m_name; + const char* m_file; + int m_line; + + bool operator==(const SubcaseSignature& other) const; + bool operator<(const SubcaseSignature& other) const; +}; + +struct DOCTEST_INTERFACE IContextScope +{ + DOCTEST_DECLARE_INTERFACE(IContextScope) + virtual void stringify(std::ostream*) const = 0; +}; + +namespace detail { + struct DOCTEST_INTERFACE TestCase; +} // namespace detail + +struct ContextOptions //!OCLINT too many fields +{ + std::ostream* cout = nullptr; // stdout stream + String binary_name; // the test binary name + + const detail::TestCase* currentTest = nullptr; + + // == parameters from the command line + String out; // output filename + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + int subcase_filter_levels; // apply the subcase filters for the first N levels + + bool success; // include successful assertions in output + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool duration; // print the time duration of each test case + bool minimal; // minimal console output (only test failures) + bool quiet; // no console output + bool no_throw; // to skip exceptions-related assertion macros + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_intro; // to not print the intro of the framework + bool no_version; // to not print the version of the framework + bool no_colors; // if output to the console should be colorized + bool force_colors; // forces the use of colors even when a tty cannot be detected + bool no_breaks; // to not break into the debugger + bool no_skip; // don't skip test cases which are marked to be skipped + bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): + bool no_path_in_filenames; // if the path to files should be removed from the output + bool no_line_numbers; // if source code line numbers should be omitted from the output + bool no_debug_output; // no output in the debug console when a debugger is attached + bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! + bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retrieved + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + bool list_reporters; // lists all registered reporters +}; + +namespace detail { + namespace types { +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + using namespace std; +#else + template + struct enable_if { }; + + template + struct enable_if { using type = T; }; + + struct true_type { static DOCTEST_CONSTEXPR bool value = true; }; + struct false_type { static DOCTEST_CONSTEXPR bool value = false; }; + + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + + template struct is_rvalue_reference : false_type { }; + template struct is_rvalue_reference : true_type { }; + + template struct remove_const { using type = T; }; + template struct remove_const { using type = T; }; + + // Compiler intrinsics + template struct is_enum { static DOCTEST_CONSTEXPR bool value = __is_enum(T); }; + template struct underlying_type { using type = __underlying_type(T); }; + + template struct is_pointer : false_type { }; + template struct is_pointer : true_type { }; + + template struct is_array : false_type { }; + // NOLINTNEXTLINE(*-avoid-c-arrays) + template struct is_array : true_type { }; +#endif + } + + // + template + T&& declval(); + + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type& t) DOCTEST_NOEXCEPT { + return static_cast(t); + } + + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type&& t) DOCTEST_NOEXCEPT { + return static_cast(t); + } + + template + struct deferred_false : types::false_type { }; + +// MSVS 2015 :( +#if !DOCTEST_CLANG && defined(_MSC_VER) && _MSC_VER <= 1900 + template + struct has_global_insertion_operator : types::false_type { }; + + template + struct has_global_insertion_operator(), declval()), void())> : types::true_type { }; + + template + struct has_insertion_operator { static DOCTEST_CONSTEXPR bool value = has_global_insertion_operator::value; }; + + template + struct insert_hack; + + template + struct insert_hack { + static void insert(std::ostream& os, const T& t) { ::operator<<(os, t); } + }; + + template + struct insert_hack { + static void insert(std::ostream& os, const T& t) { operator<<(os, t); } + }; + + template + using insert_hack_t = insert_hack::value>; +#else + template + struct has_insertion_operator : types::false_type { }; +#endif + + template + struct has_insertion_operator(), declval()), void())> : types::true_type { }; + + template + struct should_stringify_as_underlying_type { + static DOCTEST_CONSTEXPR bool value = detail::types::is_enum::value && !doctest::detail::has_insertion_operator::value; + }; + + DOCTEST_INTERFACE std::ostream* tlssPush(); + DOCTEST_INTERFACE String tlssPop(); + + template + struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T)) { +#ifdef DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES + static_assert(deferred_false::value, "No stringification detected for type T. See string conversion manual"); +#endif + return "{?}"; + } + }; + + template + struct filldata; + + template + void filloss(std::ostream* stream, const T& in) { + filldata::fill(stream, in); + } + + template + void filloss(std::ostream* stream, const T (&in)[N]) { // NOLINT(*-avoid-c-arrays) + // T[N], T(&)[N], T(&&)[N] have same behaviour. + // Hence remove reference. + filloss::type>(stream, in); + } + + template + String toStream(const T& in) { + std::ostream* stream = tlssPush(); + filloss(stream, in); + return tlssPop(); + } + + template <> + struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + return toStream(in); + } + }; +} // namespace detail + +template +struct StringMaker : public detail::StringMakerBase< + detail::has_insertion_operator::value || detail::types::is_pointer::value || detail::types::is_array::value> +{}; + +#ifndef DOCTEST_STRINGIFY +#ifdef DOCTEST_CONFIG_DOUBLE_STRINGIFY +#define DOCTEST_STRINGIFY(...) toString(toString(__VA_ARGS__)) +#else +#define DOCTEST_STRINGIFY(...) toString(__VA_ARGS__) +#endif +#endif + +template +String toString() { +#if DOCTEST_CLANG == 0 && DOCTEST_GCC == 0 && DOCTEST_ICC == 0 + String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString(void) + String::size_type beginPos = ret.find('<'); + return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast(sizeof(">(void)"))); +#else + String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE] + String::size_type begin = ret.find('=') + 2; + return ret.substr(begin, ret.size() - begin - 1); +#endif +} + +template ::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +DOCTEST_INTERFACE String toString(const std::string& in); +#endif // VS 2019 + +DOCTEST_INTERFACE String toString(String in); + +DOCTEST_INTERFACE String toString(std::nullptr_t); + +DOCTEST_INTERFACE String toString(bool in); + +DOCTEST_INTERFACE String toString(float in); +DOCTEST_INTERFACE String toString(double in); +DOCTEST_INTERFACE String toString(double long in); + +DOCTEST_INTERFACE String toString(char in); +DOCTEST_INTERFACE String toString(char signed in); +DOCTEST_INTERFACE String toString(char unsigned in); +DOCTEST_INTERFACE String toString(short in); +DOCTEST_INTERFACE String toString(short unsigned in); +DOCTEST_INTERFACE String toString(signed in); +DOCTEST_INTERFACE String toString(unsigned in); +DOCTEST_INTERFACE String toString(long in); +DOCTEST_INTERFACE String toString(long unsigned in); +DOCTEST_INTERFACE String toString(long long in); +DOCTEST_INTERFACE String toString(long long unsigned in); + +template ::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + using UT = typename detail::types::underlying_type::type; + return (DOCTEST_STRINGIFY(static_cast(value))); +} + +namespace detail { + template + struct filldata + { + static void fill(std::ostream* stream, const T& in) { +#if defined(_MSC_VER) && _MSC_VER <= 1900 + insert_hack_t::insert(*stream, in); +#else + operator<<(*stream, in); +#endif + } + }; + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) +// NOLINTBEGIN(*-avoid-c-arrays) + template + struct filldata { + static void fill(std::ostream* stream, const T(&in)[N]) { + *stream << "["; + for (size_t i = 0; i < N; i++) { + if (i != 0) { *stream << ", "; } + *stream << (DOCTEST_STRINGIFY(in[i])); + } + *stream << "]"; + } + }; +// NOLINTEND(*-avoid-c-arrays) +DOCTEST_MSVC_SUPPRESS_WARNING_POP + + // Specialized since we don't want the terminating null byte! +// NOLINTBEGIN(*-avoid-c-arrays) + template + struct filldata { + static void fill(std::ostream* stream, const char (&in)[N]) { + *stream << String(in, in[N - 1] ? N : N - 1); + } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + }; +// NOLINTEND(*-avoid-c-arrays) + + template <> + struct filldata { + static void fill(std::ostream* stream, const void* in); + }; + + template + struct filldata { +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4180) + static void fill(std::ostream* stream, const T* in) { +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wmicrosoft-cast") + filldata::fill(stream, +#if DOCTEST_GCC == 0 || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + reinterpret_cast(in) +#else + *reinterpret_cast(&in) +#endif + ); +DOCTEST_CLANG_SUPPRESS_WARNING_POP + } + }; +} + +struct DOCTEST_INTERFACE Approx +{ + Approx(double value); + + Approx operator()(double value) const; + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + explicit Approx(const T& value, + typename detail::types::enable_if::value>::type* = + static_cast(nullptr)) { + *this = static_cast(value); + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx& epsilon(double newEpsilon); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx&>::type epsilon( + const T& newEpsilon) { + m_epsilon = static_cast(newEpsilon); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx& scale(double newScale); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx&>::type scale( + const T& newScale) { + m_scale = static_cast(newScale); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format off + DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template friend typename std::enable_if::value, bool>::type + + DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(static_cast(lhs), rhs); } + DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } + DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return static_cast(lhs) < rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return static_cast(lhs) > rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return static_cast(lhs) < rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < static_cast(rhs) && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return static_cast(lhs) > rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > static_cast(rhs) && lhs != rhs; } +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format on + + double m_epsilon; + double m_scale; + double m_value; +}; + +DOCTEST_INTERFACE String toString(const Approx& in); + +DOCTEST_INTERFACE const ContextOptions* getContextOptions(); + +template +struct DOCTEST_INTERFACE_DECL IsNaN +{ + F value; bool flipped; + IsNaN(F f, bool flip = false) : value(f), flipped(flip) { } + IsNaN operator!() const { return { value, !flipped }; } + operator bool() const; +}; +#ifndef __MINGW32__ +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +#endif +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace detail { + // clang-format off +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + template struct decay_array { using type = T; }; + template struct decay_array { using type = T*; }; + template struct decay_array { using type = T*; }; + + template struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 1; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; + template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; + + template struct can_use_op : public not_char_pointer::type> {}; +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + + struct DOCTEST_INTERFACE TestFailureException + { + }; + + DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_NORETURN +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_INTERFACE void throwException(); + + struct DOCTEST_INTERFACE Subcase + { + SubcaseSignature m_signature; + bool m_entered = false; + + Subcase(const String& name, const char* file, int line); + Subcase(const Subcase&) = delete; + Subcase(Subcase&&) = delete; + Subcase& operator=(const Subcase&) = delete; + Subcase& operator=(Subcase&&) = delete; + ~Subcase(); + + operator bool() const; + + private: + bool checkFilters(); + }; + + template + String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, + const DOCTEST_REF_WRAP(R) rhs) { + return (DOCTEST_STRINGIFY(lhs)) + op + (DOCTEST_STRINGIFY(rhs)); + } + +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") +#endif + +// This will check if there is any way it could find a operator like member or friend and uses it. +// If not it doesn't find the operator or if the operator at global scope is defined after +// this template, the template won't be instantiated due to SFINAE. Once the template is not +// instantiated it can look for global operator using normal conversions. +#ifdef __NVCC__ +#define SFINAE_OP(ret,op) ret +#else +#define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval() op doctest::detail::declval()),ret{}) +#endif + +#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ + template \ + DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \ + bool res = op_macro(doctest::detail::forward(lhs), doctest::detail::forward(rhs)); \ + if(m_at & assertType::is_false) \ + res = !res; \ + if(!res || doctest::getContextOptions()->success) \ + return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ + return Result(res); \ + } + + // more checks could be added - like in Catch: + // https://github.com/catchorg/Catch2/pull/1480/files + // https://github.com/catchorg/Catch2/pull/1481/files +#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ + template \ + rt& operator op(const R&) { \ + static_assert(deferred_false::value, \ + "Expression Too Complex Please Rewrite As Binary Comparison!"); \ + return *this; \ + } + + struct DOCTEST_INTERFACE Result // NOLINT(*-member-init) + { + bool m_passed; + String m_decomp; + + Result() = default; // TODO: Why do we need this? (To remove NOLINT) + Result(bool passed, const String& decomposition = String()); + + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Result, &) + DOCTEST_FORBIT_EXPRESSION(Result, ^) + DOCTEST_FORBIT_EXPRESSION(Result, |) + DOCTEST_FORBIT_EXPRESSION(Result, &&) + DOCTEST_FORBIT_EXPRESSION(Result, ||) + DOCTEST_FORBIT_EXPRESSION(Result, ==) + DOCTEST_FORBIT_EXPRESSION(Result, !=) + DOCTEST_FORBIT_EXPRESSION(Result, <) + DOCTEST_FORBIT_EXPRESSION(Result, >) + DOCTEST_FORBIT_EXPRESSION(Result, <=) + DOCTEST_FORBIT_EXPRESSION(Result, >=) + DOCTEST_FORBIT_EXPRESSION(Result, =) + DOCTEST_FORBIT_EXPRESSION(Result, +=) + DOCTEST_FORBIT_EXPRESSION(Result, -=) + DOCTEST_FORBIT_EXPRESSION(Result, *=) + DOCTEST_FORBIT_EXPRESSION(Result, /=) + DOCTEST_FORBIT_EXPRESSION(Result, %=) + DOCTEST_FORBIT_EXPRESSION(Result, <<=) + DOCTEST_FORBIT_EXPRESSION(Result, >>=) + DOCTEST_FORBIT_EXPRESSION(Result, &=) + DOCTEST_FORBIT_EXPRESSION(Result, ^=) + DOCTEST_FORBIT_EXPRESSION(Result, |=) + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_GCC_SUPPRESS_WARNING_PUSH + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH + // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 + DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch + //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + // clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE typename types::enable_if::value || can_use_op::value, bool>::type + inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } + inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } + inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } + inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } + inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } + inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, \ + const DOCTEST_REF_WRAP(R) rhs) { \ + return lhs op rhs; \ + } + + DOCTEST_RELATIONAL_OP(eq, ==) + DOCTEST_RELATIONAL_OP(ne, !=) + DOCTEST_RELATIONAL_OP(lt, <) + DOCTEST_RELATIONAL_OP(gt, >) + DOCTEST_RELATIONAL_OP(le, <=) + DOCTEST_RELATIONAL_OP(ge, >=) + +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) l == r +#define DOCTEST_CMP_NE(l, r) l != r +#define DOCTEST_CMP_GT(l, r) l > r +#define DOCTEST_CMP_LT(l, r) l < r +#define DOCTEST_CMP_GE(l, r) l >= r +#define DOCTEST_CMP_LE(l, r) l <= r +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) eq(l, r) +#define DOCTEST_CMP_NE(l, r) ne(l, r) +#define DOCTEST_CMP_GT(l, r) gt(l, r) +#define DOCTEST_CMP_LT(l, r) lt(l, r) +#define DOCTEST_CMP_GE(l, r) ge(l, r) +#define DOCTEST_CMP_LE(l, r) le(l, r) +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + + template + // cppcheck-suppress copyCtorAndEqOperator + struct Expression_lhs + { + L lhs; + assertType::Enum m_at; + + explicit Expression_lhs(L&& in, assertType::Enum at) + : lhs(static_cast(in)) + , m_at(at) {} + + DOCTEST_NOINLINE operator Result() { +// this is needed only for MSVC 2015 +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool + bool res = static_cast(lhs); +DOCTEST_MSVC_SUPPRESS_WARNING_POP + if(m_at & assertType::is_false) { //!OCLINT bitwise operator in conditional + res = !res; + } + + if(!res || getContextOptions()->success) { + return { res, (DOCTEST_STRINGIFY(lhs)) }; + } + return { res }; + } + + /* This is required for user-defined conversions from Expression_lhs to L */ + operator L() const { return lhs; } + + // clang-format off + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional + // clang-format on + + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) + // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the + // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_POP +#endif + + struct DOCTEST_INTERFACE ExpressionDecomposer + { + assertType::Enum m_at; + + ExpressionDecomposer(assertType::Enum at); + + // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) + // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... + // https://github.com/catchorg/Catch2/issues/870 + // https://github.com/catchorg/Catch2/issues/565 + template + Expression_lhs operator<<(L&& operand) { + return Expression_lhs(static_cast(operand), m_at); + } + + template ::value,void >::type* = nullptr> + Expression_lhs operator<<(const L &operand) { + return Expression_lhs(operand, m_at); + } + }; + + struct DOCTEST_INTERFACE TestSuite + { + const char* m_test_suite = nullptr; + const char* m_description = nullptr; + bool m_skip = false; + bool m_no_breaks = false; + bool m_no_output = false; + bool m_may_fail = false; + bool m_should_fail = false; + int m_expected_failures = 0; + double m_timeout = 0; + + TestSuite& operator*(const char* in); + + template + TestSuite& operator*(const T& in) { + in.fill(*this); + return *this; + } + }; + + using funcType = void (*)(); + + struct DOCTEST_INTERFACE TestCase : public TestCaseData + { + funcType m_test; // a function pointer to the test case + + String m_type; // for templated test cases - gets appended to the real name + int m_template_id; // an ID used to distinguish between the different versions of a templated test case + String m_full_name; // contains the name (only for templated test cases!) + the template type + + TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const String& type = String(), int template_id = -1); + + TestCase(const TestCase& other); + TestCase(TestCase&&) = delete; + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& operator=(const TestCase& other); + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase& operator=(TestCase&&) = delete; + + TestCase& operator*(const char* in); + + template + TestCase& operator*(const T& in) { + in.fill(*this); + return *this; + } + + bool operator<(const TestCase& other) const; + + ~TestCase() = default; + }; + + // forward declarations of functions used by the macros + DOCTEST_INTERFACE int regTest(const TestCase& tc); + DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + DOCTEST_INTERFACE bool isDebuggerActive(); + + template + int instantiationHelper(const T&) { return 0; } + + namespace binaryAssertComparison { + enum Enum + { + eq = 0, + ne, + gt, + lt, + ge, + le + }; + } // namespace binaryAssertComparison + + // clang-format off + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; + +#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; + // clang-format on + + DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq) + DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne) + DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt) + DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt) + DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge) + DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le) + + struct DOCTEST_INTERFACE ResultBuilder : public AssertData + { + ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type = "", const String& exception_string = ""); + + ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const Contains& exception_string); + + void setResult(const Result& res); + + template + DOCTEST_NOINLINE bool binary_assert(const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + m_failed = !RelationalComparator()(lhs, rhs); + if (m_failed || getContextOptions()->success) { + m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); + } + return !m_failed; + } + + template + DOCTEST_NOINLINE bool unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_failed = !val; + + if (m_at & assertType::is_false) { //!OCLINT bitwise operator in conditional + m_failed = !m_failed; + } + + if (m_failed || getContextOptions()->success) { + m_decomp = (DOCTEST_STRINGIFY(val)); + } + + return !m_failed; + } + + void translateException(); + + bool log(); + void react() const; + }; + + namespace assertAction { + enum Enum + { + nothing = 0, + dbgbreak = 1, + shouldthrow = 2 + }; + } // namespace assertAction + + DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); + + DOCTEST_INTERFACE bool decomp_assert(assertType::Enum at, const char* file, int line, + const char* expr, const Result& result); + +#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ + do { \ + if(!is_running_in_test) { \ + if(failed) { \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + rb.m_decomp = decomp; \ + failed_out_of_a_testing_context(rb); \ + if(isDebuggerActive() && !getContextOptions()->no_breaks) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(checkIfShouldThrow(at)) \ + throwException(); \ + } \ + return !failed; \ + } \ + } while(false) + +#define DOCTEST_ASSERT_IN_TESTS(decomp) \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + if(rb.m_failed || getContextOptions()->success) \ + rb.m_decomp = decomp; \ + if(rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(rb.m_failed && checkIfShouldThrow(at)) \ + throwException() + + template + DOCTEST_NOINLINE bool binary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + bool failed = !RelationalComparator()(lhs, rhs); + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + return !failed; + } + + template + DOCTEST_NOINLINE bool unary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) val) { + bool failed = !val; + + if(at & assertType::is_false) //!OCLINT bitwise operator in conditional + failed = !failed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS((DOCTEST_STRINGIFY(val))); + DOCTEST_ASSERT_IN_TESTS((DOCTEST_STRINGIFY(val))); + return !failed; + } + + struct DOCTEST_INTERFACE IExceptionTranslator + { + DOCTEST_DECLARE_INTERFACE(IExceptionTranslator) + virtual bool translate(String&) const = 0; + }; + + template + class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class + { + public: + explicit ExceptionTranslator(String (*translateFunction)(T)) + : m_translateFunction(translateFunction) {} + + bool translate(String& res) const override { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { + throw; // lgtm [cpp/rethrow-no-exception] + // cppcheck-suppress catchExceptionByValue + } catch(const T& ex) { + res = m_translateFunction(ex); //!OCLINT parameter reassignment + return true; + } catch(...) {} //!OCLINT - empty catch statement +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + static_cast(res); // to silence -Wunused-parameter + return false; + } + + private: + String (*m_translateFunction)(T); + }; + + DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et); + + // ContextScope base class used to allow implementing methods of ContextScope + // that don't depend on the template parameter in doctest.cpp. + struct DOCTEST_INTERFACE ContextScopeBase : public IContextScope { + ContextScopeBase(const ContextScopeBase&) = delete; + + ContextScopeBase& operator=(const ContextScopeBase&) = delete; + ContextScopeBase& operator=(ContextScopeBase&&) = delete; + + ~ContextScopeBase() override = default; + + protected: + ContextScopeBase(); + ContextScopeBase(ContextScopeBase&& other) noexcept; + + void destroy(); + bool need_to_destroy{true}; + }; + + template class ContextScope : public ContextScopeBase + { + L lambda_; + + public: + explicit ContextScope(const L &lambda) : lambda_(lambda) {} + explicit ContextScope(L&& lambda) : lambda_(static_cast(lambda)) { } + + ContextScope(const ContextScope&) = delete; + ContextScope(ContextScope&&) noexcept = default; + + ContextScope& operator=(const ContextScope&) = delete; + ContextScope& operator=(ContextScope&&) = delete; + + void stringify(std::ostream* s) const override { lambda_(s); } + + ~ContextScope() override { + if (need_to_destroy) { + destroy(); + } + } + }; + + struct DOCTEST_INTERFACE MessageBuilder : public MessageData + { + std::ostream* m_stream; + bool logged = false; + + MessageBuilder(const char* file, int line, assertType::Enum severity); + + MessageBuilder(const MessageBuilder&) = delete; + MessageBuilder(MessageBuilder&&) = delete; + + MessageBuilder& operator=(const MessageBuilder&) = delete; + MessageBuilder& operator=(MessageBuilder&&) = delete; + + ~MessageBuilder(); + + // the preferred way of chaining parameters for stringification +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) + template + MessageBuilder& operator,(const T& in) { + *m_stream << (DOCTEST_STRINGIFY(in)); + return *this; + } +DOCTEST_MSVC_SUPPRESS_WARNING_POP + + // kept here just for backwards-compatibility - the comma operator should be preferred now + template + MessageBuilder& operator<<(const T& in) { return this->operator,(in); } + + // the `,` operator has the lowest operator precedence - if `<<` is used by the user then + // the `,` operator will be called last which is not what we want and thus the `*` operator + // is used first (has higher operator precedence compared to `<<`) so that we guarantee that + // an operator of the MessageBuilder class is called first before the rest of the parameters + template + MessageBuilder& operator*(const T& in) { return this->operator,(in); } + + bool log(); + void react(); + }; + + template + ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); + } +} // namespace detail + +#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ + struct name \ + { \ + type data; \ + name(type in = def) \ + : data(in) {} \ + void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + } + +DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); +DOCTEST_DEFINE_DECORATOR(description, const char*, ""); +DOCTEST_DEFINE_DECORATOR(skip, bool, true); +DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true); +DOCTEST_DEFINE_DECORATOR(no_output, bool, true); +DOCTEST_DEFINE_DECORATOR(timeout, double, 0); +DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); + +template +int registerExceptionTranslator(String (*translateFunction)(T)) { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") + static detail::ExceptionTranslator exceptionTranslator(translateFunction); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + detail::registerExceptionTranslatorImpl(&exceptionTranslator); + return 0; +} + +} // namespace doctest + +// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro +// introduces an anonymous namespace in which getCurrentTestSuite gets overridden +namespace doctest_detail_test_suite_ns { +DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +#else // DOCTEST_CONFIG_DISABLE +template +int registerExceptionTranslator(String (*)(T)) { + return 0; +} +#endif // DOCTEST_CONFIG_DISABLE + +namespace detail { + using assert_handler = void (*)(const AssertData&); + struct ContextState; +} // namespace detail + +class DOCTEST_INTERFACE Context +{ + detail::ContextState* p; + + void parseArgs(int argc, const char* const* argv, bool withDefaults = false); + +public: + explicit Context(int argc = 0, const char* const* argv = nullptr); + + Context(const Context&) = delete; + Context(Context&&) = delete; + + Context& operator=(const Context&) = delete; + Context& operator=(Context&&) = delete; + + ~Context(); // NOLINT(performance-trivially-destructible) + + void applyCommandLine(int argc, const char* const* argv); + + void addFilter(const char* filter, const char* value); + void clearFilters(); + void setOption(const char* option, bool value); + void setOption(const char* option, int value); + void setOption(const char* option, const char* value); + + bool shouldExit(); + + void setAsDefaultForAssertsOutOfTestCases(); + + void setAssertHandler(detail::assert_handler ah); + + void setCout(std::ostream* out); + + int run(); +}; + +namespace TestCaseFailureReason { + enum Enum + { + None = 0, + AssertFailure = 1, // an assertion has failed in the test case + Exception = 2, // test case threw an exception + Crash = 4, // a crash... + TooManyFailedAsserts = 8, // the abort-after option + Timeout = 16, // see the timeout decorator + ShouldHaveFailedButDidnt = 32, // see the should_fail decorator + ShouldHaveFailedAndDid = 64, // see the should_fail decorator + DidntFailExactlyNumTimes = 128, // see the expected_failures decorator + FailedExactlyNumTimes = 256, // see the expected_failures decorator + CouldHaveFailedAndDid = 512 // see the may_fail decorator + }; +} // namespace TestCaseFailureReason + +struct DOCTEST_INTERFACE CurrentTestCaseStats +{ + int numAssertsCurrentTest; + int numAssertsFailedCurrentTest; + double seconds; + int failure_flags; // use TestCaseFailureReason::Enum + bool testCaseSuccess; +}; + +struct DOCTEST_INTERFACE TestCaseException +{ + String error_string; + bool is_crash; +}; + +struct DOCTEST_INTERFACE TestRunStats +{ + unsigned numTestCases; + unsigned numTestCasesPassingFilters; + unsigned numTestSuitesPassingFilters; + unsigned numTestCasesFailed; + int numAsserts; + int numAssertsFailed; +}; + +struct QueryData +{ + const TestRunStats* run_stats = nullptr; + const TestCaseData** data = nullptr; + unsigned num_data = 0; +}; + +struct DOCTEST_INTERFACE IReporter +{ + // The constructor has to accept "const ContextOptions&" as a single argument + // which has most of the options for the run + a pointer to the stdout stream + // Reporter(const ContextOptions& in) + + // called when a query should be reported (listing test cases, printing the version, etc.) + virtual void report_query(const QueryData&) = 0; + + // called when the whole test run starts + virtual void test_run_start() = 0; + // called when the whole test run ends (caching a pointer to the input doesn't make sense here) + virtual void test_run_end(const TestRunStats&) = 0; + + // called when a test case is started (safe to cache a pointer to the input) + virtual void test_case_start(const TestCaseData&) = 0; + // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) + virtual void test_case_reenter(const TestCaseData&) = 0; + // called when a test case has ended + virtual void test_case_end(const CurrentTestCaseStats&) = 0; + + // called when an exception is thrown from the test case (or it crashes) + virtual void test_case_exception(const TestCaseException&) = 0; + + // called whenever a subcase is entered (don't cache pointers to the input) + virtual void subcase_start(const SubcaseSignature&) = 0; + // called whenever a subcase is exited (don't cache pointers to the input) + virtual void subcase_end() = 0; + + // called for each assert (don't cache pointers to the input) + virtual void log_assert(const AssertData&) = 0; + // called for each message (don't cache pointers to the input) + virtual void log_message(const MessageData&) = 0; + + // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator + // or isn't in the execution range (between first and last) (safe to cache a pointer to the input) + virtual void test_case_skipped(const TestCaseData&) = 0; + + DOCTEST_DECLARE_INTERFACE(IReporter) + + // can obtain all currently active contexts and stringify them if one wishes to do so + static int get_num_active_contexts(); + static const IContextScope* const* get_active_contexts(); + + // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown + static int get_num_stringified_contexts(); + static const String* get_stringified_contexts(); +}; + +namespace detail { + using reporterCreatorFunc = IReporter* (*)(const ContextOptions&); + + DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); + + template + IReporter* reporterCreator(const ContextOptions& o) { + return new Reporter(o); + } +} // namespace detail + +template +int registerReporter(const char* name, int priority, bool isReporter) { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); + return 0; +} +} // namespace doctest + +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_EMPTY [] { return false; }() +#else +#define DOCTEST_FUNC_EMPTY (void)0 +#endif + +// if registering is not disabled +#ifndef DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_SCOPE_BEGIN [&] +#define DOCTEST_FUNC_SCOPE_END () +#define DOCTEST_FUNC_SCOPE_RET(v) return v +#else +#define DOCTEST_FUNC_SCOPE_BEGIN do +#define DOCTEST_FUNC_SCOPE_END while(false) +#define DOCTEST_FUNC_SCOPE_RET(v) (void)0 +#endif + +// common code in asserts - for convenience +#define DOCTEST_ASSERT_LOG_REACT_RETURN(b) \ + if(b.log()) DOCTEST_BREAK_INTO_DEBUGGER(); \ + b.react(); \ + DOCTEST_FUNC_SCOPE_RET(!b.m_failed) + +#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) x; +#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) \ + try { \ + x; \ + } catch(...) { DOCTEST_RB.translateException(); } +#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ + static_cast(__VA_ARGS__); \ + DOCTEST_GCC_SUPPRESS_WARNING_POP +#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; +#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS + +// registers the test by initializing a dummy var with a function +#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ + global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT */ \ + doctest::detail::regTest( \ + doctest::detail::TestCase( \ + f, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ + decorators)) + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ + namespace { /* NOLINT */ \ + struct der : public base \ + { \ + void f(); \ + }; \ + static DOCTEST_INLINE_NOINLINE void func() { \ + der v; \ + v.f(); \ + } \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ + } \ + DOCTEST_INLINE_NOINLINE void der::f() // NOLINT(misc-definitions-in-headers) + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ + static void f(); \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ + static void f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ + static doctest::detail::funcType proxy() { return f; } \ + DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators) \ + static void f() + +// for registering tests +#define DOCTEST_TEST_CASE(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) + +// for registering tests in classes - requires C++17 for inline variables! +#if DOCTEST_CPLUSPLUS >= 201703L +#define DOCTEST_TEST_CASE_CLASS(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), \ + decorators) +#else // DOCTEST_TEST_CASE_CLASS +#define DOCTEST_TEST_CASE_CLASS(...) \ + TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER +#endif // DOCTEST_TEST_CASE_CLASS + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c, \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) \ + namespace doctest { \ + template <> \ + inline String toString<__VA_ARGS__>() { \ + return str; \ + } \ + } \ + static_assert(true, "") + +#define DOCTEST_TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING_AS(#__VA_ARGS__, __VA_ARGS__) + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ + template \ + static void func(); \ + namespace { /* NOLINT */ \ + template \ + struct iter; \ + template \ + struct iter> \ + { \ + iter(const char* file, unsigned line, int index) { \ + doctest::detail::regTest(doctest::detail::TestCase(func, file, line, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::toString(), \ + int(line) * 1000 + index) \ + * dec); \ + iter>(file, line, index + 1); \ + } \ + }; \ + template <> \ + struct iter> \ + { \ + iter(const char*, unsigned, int) {} \ + }; \ + } \ + template \ + static void func() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)) + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY), /* NOLINT(cert-err58-cpp, fuchsia-statically-constructed-objects) */ \ + doctest::detail::instantiationHelper( \ + DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0))) + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ + template \ + static void anon() + +#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) + +// for subcases +#define DOCTEST_SUBCASE(name) \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) + +// for grouping tests in test suites by using code blocks +#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ + namespace ns_name { namespace doctest_detail_test_suite_ns { \ + static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() noexcept { \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \ + static doctest::detail::TestSuite data{}; \ + static bool inited = false; \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ + if(!inited) { \ + data* decorators; \ + inited = true; \ + } \ + return data; \ + } \ + } \ + } \ + namespace ns_name + +#define DOCTEST_TEST_SUITE(decorators) \ + DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_)) + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators)) \ + static_assert(true, "") + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * "")) \ + using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int + +// for registering exception translators +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ + inline doctest::String translatorName(signature); \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerExceptionTranslator(translatorName)) \ + doctest::String translatorName(signature) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), \ + signature) + +// for registering reporters +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, true)) \ + static_assert(true, "") + +// for registering listeners +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, false)) \ + static_assert(true, "") + +// clang-format off +// for logging - disabling formatting because it's important to have these on 2 separate lines - see PR #557 +#define DOCTEST_INFO(...) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_), \ + DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_), \ + __VA_ARGS__) +// clang-format on + +#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \ + auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \ + [&](std::ostream* s_name) { \ + doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ + mb_name.m_stream = s_name; \ + mb_name * __VA_ARGS__; \ + }) + +#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) + +#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ + mb * __VA_ARGS__; \ + if(mb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + mb.react(); \ + } DOCTEST_FUNC_SCOPE_END + +// clang-format off +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +// clang-format on + +#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__) + +#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.setResult( \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__)) /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB) \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ + } DOCTEST_FUNC_SCOPE_END // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY( \ + DOCTEST_RB.binary_assert( \ + __VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +// necessary for _MESSAGE +#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::decomp_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ + doctest::detail::binary_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, \ + #__VA_ARGS__, __VA_ARGS__) + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) +#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) +#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) +#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) + +// clang-format off +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +// clang-format on + +#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) +#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) +#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) +#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) +#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) +#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) +#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) +#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) +#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) +#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) +#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) +#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) +#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) +#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) +#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) +#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) +#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) + +#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #expr, #__VA_ARGS__, message); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(const typename doctest::detail::types::remove_const< \ + typename doctest::detail::types::remove_reference<__VA_ARGS__>::type>::type&) {\ + DOCTEST_RB.translateException(); \ + DOCTEST_RB.m_threw_as = true; \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, expr_str, "", __VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ + } catch(...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } DOCTEST_FUNC_SCOPE_END + +// clang-format off +#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") +#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") + +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) + +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +// clang-format on + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// ================================================================================================= +// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == +// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == +// ================================================================================================= +#else // DOCTEST_CONFIG_DISABLE + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace /* NOLINT */ { \ + template \ + struct der : public base \ + { void f(); }; \ + } \ + template \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + template \ + static inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for registering tests in classes +#define DOCTEST_TEST_CASE_CLASS(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x, \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) static_assert(true, "") +#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "") + +// for typed tests +#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ + template \ + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ + template \ + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) static_assert(true, "") +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) static_assert(true, "") + +// for subcases +#define DOCTEST_SUBCASE(name) + +// for a testsuite block +#define DOCTEST_TEST_SUITE(name) namespace // NOLINT + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(name) static_assert(true, "") + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + template \ + static inline doctest::String DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature) + +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) + +#define DOCTEST_INFO(...) (static_cast(0)) +#define DOCTEST_CAPTURE(x) (static_cast(0)) +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_MESSAGE(...) (static_cast(0)) +#define DOCTEST_FAIL_CHECK(...) (static_cast(0)) +#define DOCTEST_FAIL(...) (static_cast(0)) + +#if defined(DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED) \ + && defined(DOCTEST_CONFIG_ASSERTS_RETURN_VALUES) + +#define DOCTEST_WARN(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#define DOCTEST_WARN_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() + +namespace doctest { +namespace detail { +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + bool name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs op rhs; } + + DOCTEST_RELATIONAL_OP(eq, ==) + DOCTEST_RELATIONAL_OP(ne, !=) + DOCTEST_RELATIONAL_OP(lt, <) + DOCTEST_RELATIONAL_OP(gt, >) + DOCTEST_RELATIONAL_OP(le, <=) + DOCTEST_RELATIONAL_OP(ge, >=) +} // namespace detail +} // namespace doctest + +#define DOCTEST_WARN_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_CHECK_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_WARN_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_CHECK_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_WARN_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_CHECK_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_WARN_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_CHECK_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_WARN_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_CHECK_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_WARN_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_CHECK_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_WARN_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS_WITH(expr, with, ...) [] { static_assert(false, "Exception translation is not available when doctest is disabled."); return false; }() +#define DOCTEST_CHECK_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) + +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(,,) + +#define DOCTEST_WARN_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#else // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED + +#define DOCTEST_WARN(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#endif // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED + +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC DOCTEST_FUNC_EMPTY +#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC [] { static_assert(false, "Exceptions are disabled! " \ + "Use DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS if you want to compile with exceptions disabled."); return false; }() + +#undef DOCTEST_REQUIRE +#undef DOCTEST_REQUIRE_FALSE +#undef DOCTEST_REQUIRE_MESSAGE +#undef DOCTEST_REQUIRE_FALSE_MESSAGE +#undef DOCTEST_REQUIRE_EQ +#undef DOCTEST_REQUIRE_NE +#undef DOCTEST_REQUIRE_GT +#undef DOCTEST_REQUIRE_LT +#undef DOCTEST_REQUIRE_GE +#undef DOCTEST_REQUIRE_LE +#undef DOCTEST_REQUIRE_UNARY +#undef DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_REQUIRE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_EQ DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// clang-format off +// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS +#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ +#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ +#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE +#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE +#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE +#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT +#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT +#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT +#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT +#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT +#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT +#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE +#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE +#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE +#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE +#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE +#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE + +#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY +#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY +#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__) +// clang-format on + +// BDD style macros +// clang-format off +#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) +#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) +#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) +#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) + +#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) +#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) +// clang-format on + +// == SHORT VERSIONS OF THE MACROS +#ifndef DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +#define TEST_CASE(name) DOCTEST_TEST_CASE(name) +#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name) +#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name) +#define TYPE_TO_STRING_AS(str, ...) DOCTEST_TYPE_TO_STRING_AS(str, __VA_ARGS__) +#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__) +#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id) +#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__) +#define SUBCASE(name) DOCTEST_SUBCASE(name) +#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators) +#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name) +#define TEST_SUITE_END DOCTEST_TEST_SUITE_END +#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) +#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter) +#define INFO(...) DOCTEST_INFO(__VA_ARGS__) +#define CAPTURE(x) DOCTEST_CAPTURE(x) +#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__) +#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__) +#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__) +#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__) +#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__) + +#define WARN(...) DOCTEST_WARN(__VA_ARGS__) +#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__) +#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__) +#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__) +#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__) +#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__) +#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__) +#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__) +#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__) +#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__) +#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__) +#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__) +#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__) +#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__) + +#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__) +#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__) +#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__) +#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__) +#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__) +#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__) +#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__) + +#define SCENARIO(name) DOCTEST_SCENARIO(name) +#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name) +#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__) +#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) +#define GIVEN(name) DOCTEST_GIVEN(name) +#define WHEN(name) DOCTEST_WHEN(name) +#define AND_WHEN(name) DOCTEST_AND_WHEN(name) +#define THEN(name) DOCTEST_THEN(name) +#define AND_THEN(name) DOCTEST_AND_THEN(name) + +#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__) +#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__) +#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__) +#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__) +#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__) +#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__) +#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__) +#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__) +#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__) +#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__) +#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__) +#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__) +#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__) +#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__) +#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__) +#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__) +#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__) +#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__) +#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__) +#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__) +#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__) +#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__) +#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +// KEPT FOR BACKWARDS COMPATIBILITY +#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__) +#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__) +#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__) +#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__) +#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__) +#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__) +#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__) +#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__) +#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__) +#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__) +#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__) +#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__) +#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__) +#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__) +#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__) +#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__) +#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__) +#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__) + +#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__) +#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__) +#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__) +#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__) +#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__) + +#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +#ifndef DOCTEST_CONFIG_DISABLE + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_TEST_SUITE_END(); + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#endif // DOCTEST_LIBRARY_INCLUDED + +#ifndef DOCTEST_SINGLE_HEADER +#define DOCTEST_SINGLE_HEADER +#endif // DOCTEST_SINGLE_HEADER + +#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) + +#ifndef DOCTEST_SINGLE_HEADER +#include "doctest_fwd.h" +#endif // DOCTEST_SINGLE_HEADER + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") + +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data +DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled +DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified +DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal +DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C +DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) +DOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal linkage has been removed + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN + +// required includes - will go only in one translation unit! +#include +#include +#include +// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/doctest/doctest/pull/37 +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#include +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#include +#include +#include +#ifndef DOCTEST_CONFIG_NO_MULTITHREADING +#include +#include +#define DOCTEST_DECLARE_MUTEX(name) std::mutex name; +#define DOCTEST_DECLARE_STATIC_MUTEX(name) static DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) std::lock_guard DOCTEST_ANONYMOUS(DOCTEST_ANON_LOCK_)(name); +#else // DOCTEST_CONFIG_NO_MULTITHREADING +#define DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_DECLARE_STATIC_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) +#endif // DOCTEST_CONFIG_NO_MULTITHREADING +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include +#endif // DOCTEST_PLATFORM_MAC + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#define DOCTEST_UNDEF_NOMINMAX +#endif // NOMINMAX + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#include +#endif +#include + +#else // DOCTEST_PLATFORM_WINDOWS + +#include +#include + +#endif // DOCTEST_PLATFORM_WINDOWS + +// this is a fix for https://github.com/doctest/doctest/issues/348 +// https://mail.gnome.org/archives/xml/2012-January/msg00000.html +#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) +#define STDOUT_FILENO fileno(stdout) +#endif // HAVE_UNISTD_H + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END + +// counts the number of elements in a C array +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifdef DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled +#else // DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled +#endif // DOCTEST_CONFIG_DISABLE + +#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX +#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" +#endif + +#ifndef DOCTEST_THREAD_LOCAL +#if defined(DOCTEST_CONFIG_NO_MULTITHREADING) || DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_THREAD_LOCAL +#else // DOCTEST_MSVC +#define DOCTEST_THREAD_LOCAL thread_local +#endif // DOCTEST_MSVC +#endif // DOCTEST_THREAD_LOCAL + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES +#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32 +#endif + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE +#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64 +#endif + +#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS +#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX +#else +#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" +#endif + +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS +#endif + +#ifndef DOCTEST_CDECL +#define DOCTEST_CDECL __cdecl +#endif + +namespace doctest { + +bool is_running_in_test = false; + +namespace { + using namespace detail; + + template + DOCTEST_NORETURN void throw_exception(Ex const& e) { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + throw e; +#else // DOCTEST_CONFIG_NO_EXCEPTIONS +#ifdef DOCTEST_CONFIG_HANDLE_EXCEPTION + DOCTEST_CONFIG_HANDLE_EXCEPTION(e); +#else // DOCTEST_CONFIG_HANDLE_EXCEPTION +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + std::cerr << "doctest will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#endif // DOCTEST_CONFIG_HANDLE_EXCEPTION + std::terminate(); +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } + +#ifndef DOCTEST_INTERNAL_ERROR +#define DOCTEST_INTERNAL_ERROR(msg) \ + throw_exception(std::logic_error( \ + __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) +#endif // DOCTEST_INTERNAL_ERROR + + // case insensitive strcmp + int stricmp(const char* a, const char* b) { + for(;; a++, b++) { + const int d = tolower(*a) - tolower(*b); + if(d != 0 || !*a) + return d; + } + } + + struct Endianness + { + enum Arch + { + Big, + Little + }; + + static Arch which() { + int x = 1; + // casting any data pointer to char* is allowed + auto ptr = reinterpret_cast(&x); + if(*ptr) + return Little; + return Big; + } + }; +} // namespace + +namespace detail { + DOCTEST_THREAD_LOCAL class + { + std::vector stack; + std::stringstream ss; + + public: + std::ostream* push() { + stack.push_back(ss.tellp()); + return &ss; + } + + String pop() { + if (stack.empty()) + DOCTEST_INTERNAL_ERROR("TLSS was empty when trying to pop!"); + + std::streampos pos = stack.back(); + stack.pop_back(); + unsigned sz = static_cast(ss.tellp() - pos); + ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out); + return String(ss, sz); + } + } g_oss; + + std::ostream* tlssPush() { + return g_oss.push(); + } + + String tlssPop() { + return g_oss.pop(); + } + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace timer_large_integer +{ + +#if defined(DOCTEST_PLATFORM_WINDOWS) + using type = ULONGLONG; +#else // DOCTEST_PLATFORM_WINDOWS + using type = std::uint64_t; +#endif // DOCTEST_PLATFORM_WINDOWS +} + +using ticks_t = timer_large_integer::type; + +#ifdef DOCTEST_CONFIG_GETCURRENTTICKS + ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } +#elif defined(DOCTEST_PLATFORM_WINDOWS) + ticks_t getCurrentTicks() { + static LARGE_INTEGER hz = { {0} }, hzo = { {0} }; + if(!hz.QuadPart) { + QueryPerformanceFrequency(&hz); + QueryPerformanceCounter(&hzo); + } + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; + } +#else // DOCTEST_PLATFORM_WINDOWS + ticks_t getCurrentTicks() { + timeval t; + gettimeofday(&t, nullptr); + return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); + } +#endif // DOCTEST_PLATFORM_WINDOWS + + struct Timer + { + void start() { m_ticks = getCurrentTicks(); } + unsigned int getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + //unsigned int getElapsedMilliseconds() const { + // return static_cast(getElapsedMicroseconds() / 1000); + //} + double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } + + private: + ticks_t m_ticks = 0; + }; + +#ifdef DOCTEST_CONFIG_NO_MULTITHREADING + template + using Atomic = T; +#else // DOCTEST_CONFIG_NO_MULTITHREADING + template + using Atomic = std::atomic; +#endif // DOCTEST_CONFIG_NO_MULTITHREADING + +#if defined(DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS) || defined(DOCTEST_CONFIG_NO_MULTITHREADING) + template + using MultiLaneAtomic = Atomic; +#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS + // Provides a multilane implementation of an atomic variable that supports add, sub, load, + // store. Instead of using a single atomic variable, this splits up into multiple ones, + // each sitting on a separate cache line. The goal is to provide a speedup when most + // operations are modifying. It achieves this with two properties: + // + // * Multiple atomics are used, so chance of congestion from the same atomic is reduced. + // * Each atomic sits on a separate cache line, so false sharing is reduced. + // + // The disadvantage is that there is a small overhead due to the use of TLS, and load/store + // is slower because all atomics have to be accessed. + template + class MultiLaneAtomic + { + struct CacheLineAlignedAtomic + { + Atomic atomic{}; + char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(Atomic)]; + }; + CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES]; + + static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE, + "guarantee one atomic takes exactly one cache line"); + + public: + T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; } + + T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); } + + T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_add(arg, order); + } + + T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_sub(arg, order); + } + + operator T() const DOCTEST_NOEXCEPT { return load(); } + + T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT { + auto result = T(); + for(auto const& c : m_atomics) { + result += c.atomic.load(order); + } + return result; + } + + T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm [cpp/assignment-does-not-return-this] + store(desired); + return desired; + } + + void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + // first value becomes desired", all others become 0. + for(auto& c : m_atomics) { + c.atomic.store(desired, order); + desired = {}; + } + } + + private: + // Each thread has a different atomic that it operates on. If more than NumLanes threads + // use this, some will use the same atomic. So performance will degrade a bit, but still + // everything will work. + // + // The logic here is a bit tricky. The call should be as fast as possible, so that there + // is minimal to no overhead in determining the correct atomic for the current thread. + // + // 1. A global static counter laneCounter counts continuously up. + // 2. Each successive thread will use modulo operation of that counter so it gets an atomic + // assigned in a round-robin fashion. + // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with + // little overhead. + Atomic& myAtomic() DOCTEST_NOEXCEPT { + static Atomic laneCounter; + DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = + laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; + + return m_atomics[tlsLaneIdx].atomic; + } + }; +#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS + + // this holds both parameters from the command line and runtime data for tests + struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats + { + MultiLaneAtomic numAssertsCurrentTest_atomic; + MultiLaneAtomic numAssertsFailedCurrentTest_atomic; + + std::vector> filters = decltype(filters)(9); // 9 different filters + + std::vector reporters_currently_used; + + assert_handler ah = nullptr; + + Timer timer; + + std::vector stringifiedContexts; // logging from INFO() due to an exception + + // stuff for subcases + bool reachedLeaf; + std::vector subcaseStack; + std::vector nextSubcaseStack; + std::unordered_set fullyTraversedSubcases; + size_t currentSubcaseDepth; + Atomic shouldLogCurrentException; + + void resetRunData() { + numTestCases = 0; + numTestCasesPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numTestCasesFailed = 0; + numAsserts = 0; + numAssertsFailed = 0; + numAssertsCurrentTest = 0; + numAssertsFailedCurrentTest = 0; + } + + void finalizeTestCaseData() { + seconds = timer.getElapsedSeconds(); + + // update the non-atomic counters + numAsserts += numAssertsCurrentTest_atomic; + numAssertsFailed += numAssertsFailedCurrentTest_atomic; + numAssertsCurrentTest = numAssertsCurrentTest_atomic; + numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; + + if(numAssertsFailedCurrentTest) + failure_flags |= TestCaseFailureReason::AssertFailure; + + if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && + Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) + failure_flags |= TestCaseFailureReason::Timeout; + + if(currentTest->m_should_fail) { + if(failure_flags) { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; + } else { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; + } + } else if(failure_flags && currentTest->m_may_fail) { + failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; + } else if(currentTest->m_expected_failures > 0) { + if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) { + failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; + } else { + failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; + } + } + + bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); + + // if any subcase has failed - the whole test case has failed + testCaseSuccess = !(failure_flags && !ok_to_fail); + if(!testCaseSuccess) + numTestCasesFailed++; + } + }; + + ContextState* g_cs = nullptr; + + // used to avoid locks for the debug output + // TODO: figure out if this is indeed necessary/correct - seems like either there still + // could be a race or that there wouldn't be a race even if using the context directly + DOCTEST_THREAD_LOCAL bool g_no_colors; + +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +char* String::allocate(size_type sz) { + if (sz <= last) { + buf[sz] = '\0'; + setLast(last - sz); + return buf; + } else { + setOnHeap(); + data.size = sz; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + data.ptr[sz] = '\0'; + return data.ptr; + } +} + +void String::setOnHeap() noexcept { *reinterpret_cast(&buf[last]) = 128; } +void String::setLast(size_type in) noexcept { buf[last] = char(in); } +void String::setSize(size_type sz) noexcept { + if (isOnStack()) { buf[sz] = '\0'; setLast(last - sz); } + else { data.ptr[sz] = '\0'; data.size = sz; } +} + +void String::copy(const String& other) { + if(other.isOnStack()) { + memcpy(buf, other.buf, len); + } else { + memcpy(allocate(other.data.size), other.data.ptr, other.data.size); + } +} + +String::String() noexcept { + buf[0] = '\0'; + setLast(); +} + +String::~String() { + if(!isOnStack()) + delete[] data.ptr; +} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +String::String(const char* in) + : String(in, strlen(in)) {} + +String::String(const char* in, size_type in_size) { + memcpy(allocate(in_size), in, in_size); +} + +String::String(std::istream& in, size_type in_size) { + in.read(allocate(in_size), in_size); +} + +String::String(const String& other) { copy(other); } + +String& String::operator=(const String& other) { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + + copy(other); + } + + return *this; +} + +String& String::operator+=(const String& other) { + const size_type my_old_size = size(); + const size_type other_size = other.size(); + const size_type total_size = my_old_size + other_size; + if(isOnStack()) { + if(total_size < len) { + // append to the current stack space + memcpy(buf + my_old_size, other.c_str(), other_size + 1); + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + setLast(last - total_size); + } else { + // alloc new chunk + char* temp = new char[total_size + 1]; + // copy current data to new location before writing in the union + memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed + // update data in union + setOnHeap(); + data.size = total_size; + data.capacity = data.size + 1; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } else { + if(data.capacity > total_size) { + // append to the current heap block + data.size = total_size; + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } else { + // resize + data.capacity *= 2; + if(data.capacity <= total_size) + data.capacity = total_size + 1; + // alloc new chunk + char* temp = new char[data.capacity]; + // copy current data to new location before releasing it + memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed + // release old chunk + delete[] data.ptr; + // update the rest of the union members + data.size = total_size; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } + + return *this; +} + +String::String(String&& other) noexcept { + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); +} + +String& String::operator=(String&& other) noexcept { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); + } + return *this; +} + +char String::operator[](size_type i) const { + return const_cast(this)->operator[](i); +} + +char& String::operator[](size_type i) { + if(isOnStack()) + return reinterpret_cast(buf)[i]; + return data.ptr[i]; +} + +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") +String::size_type String::size() const { + if(isOnStack()) + return last - (size_type(buf[last]) & 31); // using "last" would work only if "len" is 32 + return data.size; +} +DOCTEST_GCC_SUPPRESS_WARNING_POP + +String::size_type String::capacity() const { + if(isOnStack()) + return len; + return data.capacity; +} + +String String::substr(size_type pos, size_type cnt) && { + cnt = std::min(cnt, size() - 1 - pos); + char* cptr = c_str(); + memmove(cptr, cptr + pos, cnt); + setSize(cnt); + return std::move(*this); +} + +String String::substr(size_type pos, size_type cnt) const & { + cnt = std::min(cnt, size() - 1 - pos); + return String{ c_str() + pos, cnt }; +} + +String::size_type String::find(char ch, size_type pos) const { + const char* begin = c_str(); + const char* end = begin + size(); + const char* it = begin + pos; + for (; it < end && *it != ch; it++); + if (it < end) { return static_cast(it - begin); } + else { return npos; } +} + +String::size_type String::rfind(char ch, size_type pos) const { + const char* begin = c_str(); + const char* it = begin + std::min(pos, size() - 1); + for (; it >= begin && *it != ch; it--); + if (it >= begin) { return static_cast(it - begin); } + else { return npos; } +} + +int String::compare(const char* other, bool no_case) const { + if(no_case) + return doctest::stricmp(c_str(), other); + return std::strcmp(c_str(), other); +} + +int String::compare(const String& other, bool no_case) const { + return compare(other.c_str(), no_case); +} + +String operator+(const String& lhs, const String& rhs) { return String(lhs) += rhs; } + +bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } +bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } +bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } +bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } +bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } +bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } + +std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } + +Contains::Contains(const String& str) : string(str) { } + +bool Contains::checkWith(const String& other) const { + return strstr(other.c_str(), string.c_str()) != nullptr; +} + +String toString(const Contains& in) { + return "Contains( " + in.string + " )"; +} + +bool operator==(const String& lhs, const Contains& rhs) { return rhs.checkWith(lhs); } +bool operator==(const Contains& lhs, const String& rhs) { return lhs.checkWith(rhs); } +bool operator!=(const String& lhs, const Contains& rhs) { return !rhs.checkWith(lhs); } +bool operator!=(const Contains& lhs, const String& rhs) { return !lhs.checkWith(rhs); } + +namespace { + void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) +} // namespace + +namespace Color { + std::ostream& operator<<(std::ostream& s, Color::Enum code) { + color_to_stream(s, code); + return s; + } +} // namespace Color + +// clang-format off +const char* assertString(assertType::Enum at) { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4061) // enum 'x' in switch of enum 'y' is not explicitly handled + #define DOCTEST_GENERATE_ASSERT_TYPE_CASE(assert_type) case assertType::DT_ ## assert_type: return #assert_type + #define DOCTEST_GENERATE_ASSERT_TYPE_CASES(assert_type) \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN_ ## assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK_ ## assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE_ ## assert_type) + switch(at) { + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(FALSE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NOTHROW); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(EQ); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY_FALSE); + + default: DOCTEST_INTERNAL_ERROR("Tried stringifying invalid assert type!"); + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP +} +// clang-format on + +const char* failureString(assertType::Enum at) { + if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional + return "WARNING"; + if(at & assertType::is_check) //!OCLINT bitwise operator in conditional + return "ERROR"; + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return "FATAL ERROR"; + return ""; +} + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +// depending on the current options this will remove the path of filenames +const char* skipPathFromFilename(const char* file) { +#ifndef DOCTEST_CONFIG_DISABLE + if(getContextOptions()->no_path_in_filenames) { + auto back = std::strrchr(file, '\\'); + auto forward = std::strrchr(file, '/'); + if(back || forward) { + if(back > forward) + forward = back; + return forward + 1; + } + } +#endif // DOCTEST_CONFIG_DISABLE + return file; +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +bool SubcaseSignature::operator==(const SubcaseSignature& other) const { + return m_line == other.m_line + && std::strcmp(m_file, other.m_file) == 0 + && m_name == other.m_name; +} + +bool SubcaseSignature::operator<(const SubcaseSignature& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + if(std::strcmp(m_file, other.m_file) != 0) + return std::strcmp(m_file, other.m_file) < 0; + return m_name.compare(other.m_name) < 0; +} + +DOCTEST_DEFINE_INTERFACE(IContextScope) + +namespace detail { + void filldata::fill(std::ostream* stream, const void* in) { + if (in) { *stream << in; } + else { *stream << "nullptr"; } + } + + template + String toStreamLit(T t) { + std::ostream* os = tlssPush(); + os->operator<<(t); + return tlssPop(); + } +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +String toString(const std::string& in) { return in.c_str(); } +#endif // VS 2019 + +String toString(String in) { return in; } + +String toString(std::nullptr_t) { return "nullptr"; } + +String toString(bool in) { return in ? "true" : "false"; } + +String toString(float in) { return toStreamLit(in); } +String toString(double in) { return toStreamLit(in); } +String toString(double long in) { return toStreamLit(in); } + +String toString(char in) { return toStreamLit(static_cast(in)); } +String toString(char signed in) { return toStreamLit(static_cast(in)); } +String toString(char unsigned in) { return toStreamLit(static_cast(in)); } +String toString(short in) { return toStreamLit(in); } +String toString(short unsigned in) { return toStreamLit(in); } +String toString(signed in) { return toStreamLit(in); } +String toString(unsigned in) { return toStreamLit(in); } +String toString(long in) { return toStreamLit(in); } +String toString(long unsigned in) { return toStreamLit(in); } +String toString(long long in) { return toStreamLit(in); } +String toString(long long unsigned in) { return toStreamLit(in); } + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) + , m_scale(1.0) + , m_value(value) {} + +Approx Approx::operator()(double value) const { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; +} + +Approx& Approx::epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; +} +Approx& Approx::scale(double newScale) { + m_scale = newScale; + return *this; +} + +bool operator==(double lhs, const Approx& rhs) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); +} +bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } +bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } +bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } +bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; } +bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } +bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; } +bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } +bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; } +bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } +bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; } +bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } + +String toString(const Approx& in) { + return "Approx( " + doctest::toString(in.m_value) + " )"; +} +const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4738) +template +IsNaN::operator bool() const { + return std::isnan(value) ^ flipped; +} +DOCTEST_MSVC_SUPPRESS_WARNING_POP +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; +template +String toString(IsNaN in) { return String(in.flipped ? "! " : "") + "IsNaN( " + doctest::toString(in.value) + " )"; } +String toString(IsNaN in) { return toString(in); } +String toString(IsNaN in) { return toString(in); } +String toString(IsNaN in) { return toString(in); } + +} // namespace doctest + +#ifdef DOCTEST_CONFIG_DISABLE +namespace doctest { +Context::Context(int, const char* const*) {} +Context::~Context() = default; +void Context::applyCommandLine(int, const char* const*) {} +void Context::addFilter(const char*, const char*) {} +void Context::clearFilters() {} +void Context::setOption(const char*, bool) {} +void Context::setOption(const char*, int) {} +void Context::setOption(const char*, const char*) {} +bool Context::shouldExit() { return false; } +void Context::setAsDefaultForAssertsOutOfTestCases() {} +void Context::setAssertHandler(detail::assert_handler) {} +void Context::setCout(std::ostream*) {} +int Context::run() { return 0; } + +int IReporter::get_num_active_contexts() { return 0; } +const IContextScope* const* IReporter::get_active_contexts() { return nullptr; } +int IReporter::get_num_stringified_contexts() { return 0; } +const String* IReporter::get_stringified_contexts() { return nullptr; } + +int registerReporter(const char*, int, IReporter*) { return 0; } + +} // namespace doctest +#else // DOCTEST_CONFIG_DISABLE + +#if !defined(DOCTEST_CONFIG_COLORS_NONE) +#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_CONFIG_COLORS_WINDOWS +#else // linux +#define DOCTEST_CONFIG_COLORS_ANSI +#endif // platform +#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI +#endif // DOCTEST_CONFIG_COLORS_NONE + +namespace doctest_detail_test_suite_ns { +// holds the current test suite +doctest::detail::TestSuite& getCurrentTestSuite() { + static doctest::detail::TestSuite data{}; + return data; +} +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +namespace { + // the int (priority) is part of the key for automatic sorting - sadly one can register a + // reporter with a duplicate name and a different priority but hopefully that won't happen often :| + using reporterMap = std::map, reporterCreatorFunc>; + + reporterMap& getReporters() { + static reporterMap data; + return data; + } + reporterMap& getListeners() { + static reporterMap data; + return data; + } +} // namespace +namespace detail { +#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ + for(auto& curr_rep : g_cs->reporters_currently_used) \ + curr_rep->function(__VA_ARGS__) + + bool checkIfShouldThrow(assertType::Enum at) { + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return true; + + if((at & assertType::is_check) //!OCLINT bitwise operator in conditional + && getContextOptions()->abort_after > 0 && + (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= + getContextOptions()->abort_after) + return true; + + return false; + } + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_NORETURN void throwException() { + g_cs->shouldLogCurrentException = false; + throw TestFailureException(); // NOLINT(hicpp-exception-baseclass) + } +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + void throwException() {} +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +} // namespace detail + +namespace { + using namespace detail; + // matching of a string against a wildcard mask (case sensitivity configurable) taken from + // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing + int wildcmp(const char* str, const char* wild, bool caseSensitive) { + const char* cp = str; + const char* mp = wild; + + while((*str) && (*wild != '*')) { + if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && + (*wild != '?')) { + return 0; + } + wild++; + str++; + } + + while(*str) { + if(*wild == '*') { + if(!*++wild) { + return 1; + } + mp = wild; + cp = str + 1; + } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || + (*wild == '?')) { + wild++; + str++; + } else { + wild = mp; //!OCLINT parameter reassignment + str = cp++; //!OCLINT parameter reassignment + } + } + + while(*wild == '*') { + wild++; + } + return !*wild; + } + + // checks if the name matches any of the filters (and can be configured what to do when empty) + bool matchesAny(const char* name, const std::vector& filters, bool matchEmpty, + bool caseSensitive) { + if (filters.empty() && matchEmpty) + return true; + for (auto& curr : filters) + if (wildcmp(name, curr.c_str(), caseSensitive)) + return true; + return false; + } + + DOCTEST_NO_SANITIZE_INTEGER + unsigned long long hash(unsigned long long a, unsigned long long b) { + return (a << 5) + b; + } + + // C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + DOCTEST_NO_SANITIZE_INTEGER + unsigned long long hash(const char* str) { + unsigned long long hash = 5381; + char c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; // hash * 33 + c + return hash; + } + + unsigned long long hash(const SubcaseSignature& sig) { + return hash(hash(hash(sig.m_file), hash(sig.m_name.c_str())), sig.m_line); + } + + unsigned long long hash(const std::vector& sigs, size_t count) { + unsigned long long running = 0; + auto end = sigs.begin() + count; + for (auto it = sigs.begin(); it != end; it++) { + running = hash(running, hash(*it)); + } + return running; + } + + unsigned long long hash(const std::vector& sigs) { + unsigned long long running = 0; + for (const SubcaseSignature& sig : sigs) { + running = hash(running, hash(sig)); + } + return running; + } +} // namespace +namespace detail { + bool Subcase::checkFilters() { + if (g_cs->subcaseStack.size() < size_t(g_cs->subcase_filter_levels)) { + if (!matchesAny(m_signature.m_name.c_str(), g_cs->filters[6], true, g_cs->case_sensitive)) + return true; + if (matchesAny(m_signature.m_name.c_str(), g_cs->filters[7], false, g_cs->case_sensitive)) + return true; + } + return false; + } + + Subcase::Subcase(const String& name, const char* file, int line) + : m_signature({name, file, line}) { + if (!g_cs->reachedLeaf) { + if (g_cs->nextSubcaseStack.size() <= g_cs->subcaseStack.size() + || g_cs->nextSubcaseStack[g_cs->subcaseStack.size()] == m_signature) { + // Going down. + if (checkFilters()) { return; } + + g_cs->subcaseStack.push_back(m_signature); + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } + } else { + if (g_cs->subcaseStack[g_cs->currentSubcaseDepth] == m_signature) { + // This subcase is reentered via control flow. + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } else if (g_cs->nextSubcaseStack.size() <= g_cs->currentSubcaseDepth + && g_cs->fullyTraversedSubcases.find(hash(hash(g_cs->subcaseStack, g_cs->currentSubcaseDepth), hash(m_signature))) + == g_cs->fullyTraversedSubcases.end()) { + if (checkFilters()) { return; } + // This subcase is part of the one to be executed next. + g_cs->nextSubcaseStack.clear(); + g_cs->nextSubcaseStack.insert(g_cs->nextSubcaseStack.end(), + g_cs->subcaseStack.begin(), g_cs->subcaseStack.begin() + g_cs->currentSubcaseDepth); + g_cs->nextSubcaseStack.push_back(m_signature); + } + } + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + + Subcase::~Subcase() { + if (m_entered) { + g_cs->currentSubcaseDepth--; + + if (!g_cs->reachedLeaf) { + // Leaf. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + g_cs->nextSubcaseStack.clear(); + g_cs->reachedLeaf = true; + } else if (g_cs->nextSubcaseStack.empty()) { + // All children are finished. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + } + +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if(std::uncaught_exceptions() > 0 +#else + if(std::uncaught_exception() +#endif + && g_cs->shouldLogCurrentException) { + DOCTEST_ITERATE_THROUGH_REPORTERS( + test_case_exception, {"exception thrown in subcase - will translate later " + "when the whole test case has been exited (cannot " + "translate while there is an active exception)", + false}); + g_cs->shouldLogCurrentException = false; + } + + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + } + } + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + Subcase::operator bool() const { return m_entered; } + + Result::Result(bool passed, const String& decomposition) + : m_passed(passed) + , m_decomp(decomposition) {} + + ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) + : m_at(at) {} + + TestSuite& TestSuite::operator*(const char* in) { + m_test_suite = in; + return *this; + } + + TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const String& type, int template_id) { + m_file = file; + m_line = line; + m_name = nullptr; // will be later overridden in operator* + m_test_suite = test_suite.m_test_suite; + m_description = test_suite.m_description; + m_skip = test_suite.m_skip; + m_no_breaks = test_suite.m_no_breaks; + m_no_output = test_suite.m_no_output; + m_may_fail = test_suite.m_may_fail; + m_should_fail = test_suite.m_should_fail; + m_expected_failures = test_suite.m_expected_failures; + m_timeout = test_suite.m_timeout; + + m_test = test; + m_type = type; + m_template_id = template_id; + } + + TestCase::TestCase(const TestCase& other) + : TestCaseData() { + *this = other; + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& TestCase::operator=(const TestCase& other) { + TestCaseData::operator=(other); + m_test = other.m_test; + m_type = other.m_type; + m_template_id = other.m_template_id; + m_full_name = other.m_full_name; + + if(m_template_id != -1) + m_name = m_full_name.c_str(); + return *this; + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase& TestCase::operator*(const char* in) { + m_name = in; + // make a new name with an appended type for templated test case + if(m_template_id != -1) { + m_full_name = String(m_name) + "<" + m_type + ">"; + // redirect the name to point to the newly constructed full name + m_name = m_full_name.c_str(); + } + return *this; + } + + bool TestCase::operator<(const TestCase& other) const { + // this will be used only to differentiate between test cases - not relevant for sorting + if(m_line != other.m_line) + return m_line < other.m_line; + const int name_cmp = strcmp(m_name, other.m_name); + if(name_cmp != 0) + return name_cmp < 0; + const int file_cmp = m_file.compare(other.m_file); + if(file_cmp != 0) + return file_cmp < 0; + return m_template_id < other.m_template_id; + } + + // all the registered tests + std::set& getRegisteredTests() { + static std::set data; + return data; + } +} // namespace detail +namespace { + using namespace detail; + // for sorting tests by file/line + bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); + if(res != 0) + return res < 0; + if(lhs->m_line != rhs->m_line) + return lhs->m_line < rhs->m_line; + return lhs->m_template_id < rhs->m_template_id; + } + + // for sorting tests by suite/file/line + bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); + if(res != 0) + return res < 0; + return fileOrderComparator(lhs, rhs); + } + + // for sorting tests by name/suite/file/line + bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_name, rhs->m_name); + if(res != 0) + return res < 0; + return suiteOrderComparator(lhs, rhs); + } + + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + void color_to_stream(std::ostream& s, Color::Enum code) { + static_cast(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS + static_cast(code); // for DOCTEST_CONFIG_COLORS_NONE +#ifdef DOCTEST_CONFIG_COLORS_ANSI + if(g_no_colors || + (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) + return; + + auto col = ""; + // clang-format off + switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement + case Color::Red: col = "[0;31m"; break; + case Color::Green: col = "[0;32m"; break; + case Color::Blue: col = "[0;34m"; break; + case Color::Cyan: col = "[0;36m"; break; + case Color::Yellow: col = "[0;33m"; break; + case Color::Grey: col = "[1;30m"; break; + case Color::LightGrey: col = "[0;37m"; break; + case Color::BrightRed: col = "[1;31m"; break; + case Color::BrightGreen: col = "[1;32m"; break; + case Color::BrightWhite: col = "[1;37m"; break; + case Color::Bright: // invalid + case Color::None: + case Color::White: + default: col = "[0m"; + } + // clang-format on + s << "\033" << col; +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + if(g_no_colors || + (_isatty(_fileno(stdout)) == false && getContextOptions()->force_colors == false)) + return; + + static struct ConsoleHelper { + HANDLE stdoutHandle; + WORD origFgAttrs; + WORD origBgAttrs; + + ConsoleHelper() { + stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); + origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } + } ch; + +#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(ch.stdoutHandle, x | ch.origBgAttrs) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(ch.origFgAttrs); + } + // clang-format on +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP + + std::vector& getExceptionTranslators() { + static std::vector data; + return data; + } + + String translateActiveException() { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + String res; + auto& translators = getExceptionTranslators(); + for(auto& curr : translators) + if(curr->translate(res)) + return res; + // clang-format off + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") + try { + throw; + } catch(std::exception& ex) { + return ex.what(); + } catch(std::string& msg) { + return msg.c_str(); + } catch(const char* msg) { + return msg; + } catch(...) { + return "unknown exception"; + } + DOCTEST_GCC_SUPPRESS_WARNING_POP +// clang-format on +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + return ""; +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } +} // namespace + +namespace detail { + // used by the macros for registering tests + int regTest(const TestCase& tc) { + getRegisteredTests().insert(tc); + return 0; + } + + // sets the current test suite + int setTestSuite(const TestSuite& ts) { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; + } + +#ifdef DOCTEST_IS_DEBUGGER_ACTIVE + bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } +#else // DOCTEST_IS_DEBUGGER_ACTIVE +#ifdef DOCTEST_PLATFORM_LINUX + class ErrnoGuard { + public: + ErrnoGuard() : m_oldErrno(errno) {} + ~ErrnoGuard() { errno = m_oldErrno; } + private: + int m_oldErrno; + }; + // See the comments in Catch2 for the reasoning behind this implementation: + // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 + bool isDebuggerActive() { + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for(std::string line; std::getline(in, line);) { + static const int PREFIX_LEN = 11; + if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + return false; + } +#elif defined(DOCTEST_PLATFORM_MAC) + // The following function is taken directly from the following technical note: + // https://developer.apple.com/library/archive/qa/qa1361/_index.html + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { + std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } +#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) + bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } +#else + bool isDebuggerActive() { return false; } +#endif // Platform +#endif // DOCTEST_IS_DEBUGGER_ACTIVE + + void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { + if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == + getExceptionTranslators().end()) + getExceptionTranslators().push_back(et); + } + + DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() + + ContextScopeBase::ContextScopeBase() { + g_infoContexts.push_back(this); + } + + ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) noexcept { + if (other.need_to_destroy) { + other.destroy(); + } + other.need_to_destroy = false; + g_infoContexts.push_back(this); + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + + // destroy cannot be inlined into the destructor because that would mean calling stringify after + // ContextScope has been destroyed (base class destructors run after derived class destructors). + // Instead, ContextScope calls this method directly from its destructor. + void ContextScopeBase::destroy() { +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if(std::uncaught_exceptions() > 0) { +#else + if(std::uncaught_exception()) { +#endif + std::ostringstream s; + this->stringify(&s); + g_cs->stringifiedContexts.push_back(s.str().c_str()); + } + g_infoContexts.pop_back(); + } + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP +} // namespace detail +namespace { + using namespace detail; + +#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) + struct FatalConditionHandler + { + static void reset() {} + static void allocateAltStackMem() {} + static void freeAltStackMem() {} + }; +#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + + void reportFatal(const std::string&); + +#ifdef DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + DWORD id; + const char* name; + }; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + {static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), + "SIGILL - Illegal instruction signal"}, + {static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, + {static_cast(EXCEPTION_ACCESS_VIOLATION), + "SIGSEGV - Segmentation violation signal"}, + {static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, + }; + + struct FatalConditionHandler + { + static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { + // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the + // console just once no matter how many threads have crashed. + DOCTEST_DECLARE_STATIC_MUTEX(mutex) + static bool execute = true; + { + DOCTEST_LOCK_MUTEX(mutex) + if(execute) { + bool reported = false; + for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + reported = true; + break; + } + } + if(reported == false) + reportFatal("Unhandled SEH exception caught"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + } + execute = false; + } + std::exit(EXIT_FAILURE); + } + + static void allocateAltStackMem() {} + static void freeAltStackMem() {} + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for doctest to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + // Register an unhandled exception filter + previousTop = SetUnhandledExceptionFilter(handleException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + + // On Windows uncaught exceptions from another thread, exceptions from + // destructors, or calls to std::terminate are not a SEH exception + + // The terminal handler gets called when: + // - std::terminate is called FROM THE TEST RUNNER THREAD + // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD + original_terminate_handler = std::get_terminate(); + std::set_terminate([]() DOCTEST_NOEXCEPT { + reportFatal("Terminate handler called"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well + }); + + // SIGABRT is raised when: + // - std::terminate is called FROM A DIFFERENT THREAD + // - an exception is thrown from a destructor FROM A DIFFERENT THREAD + // - an uncaught exception is thrown FROM A DIFFERENT THREAD + prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT { + if(signal == SIGABRT) { + reportFatal("SIGABRT - Abort (abnormal termination) signal"); + if(isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); + } + }); + + // The following settings are taken from google test, and more + // specifically from UnitTest::Run() inside of gtest.cc + + // the user does not want to see pop-up dialogs about crashes + prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); + // This forces the abort message to go to stderr in all circumstances. + prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR); + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program - we want to disable that. + prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } + + static void reset() { + if(isSet) { + // Unregister handler and restore the old guarantee + SetUnhandledExceptionFilter(previousTop); + SetThreadStackGuarantee(&guaranteeSize); + std::set_terminate(original_terminate_handler); + std::signal(SIGABRT, prev_sigabrt_handler); + SetErrorMode(prev_error_mode_1); + _set_error_mode(prev_error_mode_2); + _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + static_cast(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode)); + static_cast(_CrtSetReportFile(_CRT_ASSERT, prev_report_file)); + isSet = false; + } + } + + ~FatalConditionHandler() { reset(); } + + private: + static UINT prev_error_mode_1; + static int prev_error_mode_2; + static unsigned int prev_abort_behavior; + static int prev_report_mode; + static _HFILE prev_report_file; + static void (DOCTEST_CDECL *prev_sigabrt_handler)(int); + static std::terminate_handler original_terminate_handler; + static bool isSet; + static ULONG guaranteeSize; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; + }; + + UINT FatalConditionHandler::prev_error_mode_1; + int FatalConditionHandler::prev_error_mode_2; + unsigned int FatalConditionHandler::prev_abort_behavior; + int FatalConditionHandler::prev_report_mode; + _HFILE FatalConditionHandler::prev_report_file; + void (DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int); + std::terminate_handler FatalConditionHandler::original_terminate_handler; + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; + +#else // DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + int id; + const char* name; + }; + SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"}, + {SIGILL, "SIGILL - Illegal instruction signal"}, + {SIGFPE, "SIGFPE - Floating point error signal"}, + {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, + {SIGTERM, "SIGTERM - Termination request signal"}, + {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; + + struct FatalConditionHandler + { + static bool isSet; + static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; + static stack_t oldSigStack; + static size_t altStackSize; + static char* altStackMem; + + static void handleSignal(int sig) { + const char* name = ""; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + SignalDefs& def = signalDefs[i]; + if(sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise(sig); + } + + static void allocateAltStackMem() { + altStackMem = new char[altStackSize]; + } + + static void freeAltStackMem() { + delete[] altStackMem; + } + + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = altStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = {}; + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + ~FatalConditionHandler() { reset(); } + static void reset() { + if(isSet) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + }; + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ; + char* FatalConditionHandler::altStackMem = nullptr; + +#endif // DOCTEST_PLATFORM_WINDOWS +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +} // namespace + +namespace { + using namespace detail; + +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) +#else + // TODO: integration with XCode and other IDEs +#define DOCTEST_OUTPUT_DEBUG_STRING(text) +#endif // Platform + + void addAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsCurrentTest_atomic++; + } + + void addFailedAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsFailedCurrentTest_atomic++; + } + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) + void reportFatal(const std::string& message) { + g_cs->failure_flags |= TestCaseFailureReason::Crash; + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); + + while (g_cs->subcaseStack.size()) { + g_cs->subcaseStack.pop_back(); + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + } + + g_cs->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH +} // namespace + +AssertData::AssertData(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const StringContains& exception_string) + : m_test_case(g_cs->currentTest), m_at(at), m_file(file), m_line(line), m_expr(expr), + m_failed(true), m_threw(false), m_threw_as(false), m_exception_type(exception_type), + m_exception_string(exception_string) { +#if DOCTEST_MSVC + if (m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC + ++m_expr; +#endif // MSVC +} + +namespace detail { + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const String& exception_string) + : AssertData(at, file, line, expr, exception_type, exception_string) { } + + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const Contains& exception_string) + : AssertData(at, file, line, expr, exception_type, exception_string) { } + + void ResultBuilder::setResult(const Result& res) { + m_decomp = res.m_decomp; + m_failed = !res.m_passed; + } + + void ResultBuilder::translateException() { + m_threw = true; + m_exception = translateActiveException(); + } + + bool ResultBuilder::log() { + if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw; + } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT + m_failed = !m_threw_as || !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw_as; + } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + m_failed = !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + m_failed = m_threw; + } + + if(m_exception.size()) + m_exception = "\"" + m_exception + "\""; + + if(is_running_in_test) { + addAssert(m_at); + DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); + + if(m_failed) + addFailedAssert(m_at); + } else if(m_failed) { + failed_out_of_a_testing_context(*this); + } + + return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger + } + + void ResultBuilder::react() const { + if(m_failed && checkIfShouldThrow(m_at)) + throwException(); + } + + void failed_out_of_a_testing_context(const AssertData& ad) { + if(g_cs->ah) + g_cs->ah(ad); + else + std::abort(); + } + + bool decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, + const Result& result) { + bool failed = !result.m_passed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); + DOCTEST_ASSERT_IN_TESTS(result.m_decomp); + return !failed; + } + + MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { + m_stream = tlssPush(); + m_file = file; + m_line = line; + m_severity = severity; + } + + MessageBuilder::~MessageBuilder() { + if (!logged) + tlssPop(); + } + + DOCTEST_DEFINE_INTERFACE(IExceptionTranslator) + + bool MessageBuilder::log() { + if (!logged) { + m_string = tlssPop(); + logged = true; + } + + DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); + + const bool isWarn = m_severity & assertType::is_warn; + + // warn is just a message in this context so we don't treat it as an assert + if(!isWarn) { + addAssert(m_severity); + addFailedAssert(m_severity); + } + + return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger + } + + void MessageBuilder::react() { + if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional + throwException(); + } +} // namespace detail +namespace { + using namespace detail; + + // clang-format off + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; + ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + XmlWriter( std::ostream& os = std::cout ); +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + XmlWriter( std::ostream& os ); +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, const char* attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::stringstream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + //XmlWriter& writeComment( std::string const& text ); + + //void writeStylesheetRef( std::string const& url ); + + //XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + void writeDeclaration(); + + private: + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + +using uchar = unsigned char; + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + os.flags(f); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: https://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: https://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + // writeDeclaration(); // called explicitly by the reporters that use the writer class - see issue #627 + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { + if( !name.empty() && attribute && attribute[0] != '\0' ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + //XmlWriter& XmlWriter::writeComment( std::string const& text ) { + // ensureTagClosed(); + // m_os << m_indent << ""; + // m_needsNewline = true; + // return *this; + //} + + //void XmlWriter::writeStylesheetRef( std::string const& url ) { + // m_os << "\n"; + //} + + //XmlWriter& XmlWriter::writeBlankLine() { + // ensureTagClosed(); + // m_os << '\n'; + // return *this; + //} + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } + +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + + // clang-format on + + struct XmlReporter : public IReporter + { + XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc = nullptr; + + XmlReporter(const ContextOptions& co) + : xml(*co.cout) + , opt(co) {} + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + std::stringstream ss; + for(int i = 0; i < num_contexts; ++i) { + contexts[i]->stringify(&ss); + xml.scopedElement("Info").writeText(ss.str()); + ss.str(""); + } + } + } + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + void test_case_start_impl(const TestCaseData& in) { + bool open_ts_tag = false; + if(tc != nullptr) { // we have already opened a test suite + if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { + xml.endElement(); + open_ts_tag = true; + } + } + else { + open_ts_tag = true; // first test case ==> first test suite + } + + if(open_ts_tag) { + xml.startElement("TestSuite"); + xml.writeAttribute("name", in.m_test_suite); + } + + tc = ∈ + xml.startElement("TestCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) + .writeAttribute("line", line(in.m_line)) + .writeAttribute("description", in.m_description); + + if(Approx(in.m_timeout) != 0) + xml.writeAttribute("timeout", in.m_timeout); + if(in.m_may_fail) + xml.writeAttribute("may_fail", true); + if(in.m_should_fail) + xml.writeAttribute("should_fail", true); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + test_run_start(); + if(opt.list_reporters) { + for(auto& curr : getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + for(auto& curr : getReporters()) + xml.scopedElement("Reporter") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + } else if(opt.count || opt.list_test_cases) { + for(unsigned i = 0; i < in.num_data; ++i) { + xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name) + .writeAttribute("testsuite", in.data[i]->m_test_suite) + .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) + .writeAttribute("line", line(in.data[i]->m_line)) + .writeAttribute("skipped", in.data[i]->m_skip); + } + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + } else if(opt.list_test_suites) { + for(unsigned i = 0; i < in.num_data; ++i) + xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + xml.scopedElement("OverallResultsTestSuites") + .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); + } + xml.endElement(); + } + + void test_run_start() override { + xml.writeDeclaration(); + + // remove .exe extension - mainly to have the same output on UNIX and Windows + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if(binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + + xml.startElement("doctest").writeAttribute("binary", binary_name); + if(opt.no_version == false) + xml.writeAttribute("version", DOCTEST_VERSION_STR); + + // only the consequential ones (TODO: filters) + xml.scopedElement("Options") + .writeAttribute("order_by", opt.order_by.c_str()) + .writeAttribute("rand_seed", opt.rand_seed) + .writeAttribute("first", opt.first) + .writeAttribute("last", opt.last) + .writeAttribute("abort_after", opt.abort_after) + .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) + .writeAttribute("case_sensitive", opt.case_sensitive) + .writeAttribute("no_throw", opt.no_throw) + .writeAttribute("no_skip", opt.no_skip); + } + + void test_run_end(const TestRunStats& p) override { + if(tc) // the TestSuite tag - only if there has been at least 1 test case + xml.endElement(); + + xml.scopedElement("OverallResultsAsserts") + .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) + .writeAttribute("failures", p.numAssertsFailed); + + xml.startElement("OverallResultsTestCases") + .writeAttribute("successes", + p.numTestCasesPassingFilters - p.numTestCasesFailed) + .writeAttribute("failures", p.numTestCasesFailed); + if(opt.no_skipped_summary == false) + xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); + xml.endElement(); + + xml.endElement(); + } + + void test_case_start(const TestCaseData& in) override { + test_case_start_impl(in); + xml.ensureTagClosed(); + } + + void test_case_reenter(const TestCaseData&) override {} + + void test_case_end(const CurrentTestCaseStats& st) override { + xml.startElement("OverallResultsAsserts") + .writeAttribute("successes", + st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) + .writeAttribute("failures", st.numAssertsFailedCurrentTest) + .writeAttribute("test_case_success", st.testCaseSuccess); + if(opt.duration) + xml.writeAttribute("duration", st.seconds); + if(tc->m_expected_failures) + xml.writeAttribute("expected_failures", tc->m_expected_failures); + xml.endElement(); + + xml.endElement(); + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + + xml.scopedElement("Exception") + .writeAttribute("crash", e.is_crash) + .writeText(e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + xml.startElement("SubCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file)) + .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); + } + + void subcase_end() override { xml.endElement(); } + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed && !opt.success) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Expression") + .writeAttribute("success", !rb.m_failed) + .writeAttribute("type", assertString(rb.m_at)) + .writeAttribute("filename", skipPathFromFilename(rb.m_file)) + .writeAttribute("line", line(rb.m_line)); + + xml.scopedElement("Original").writeText(rb.m_expr); + + if(rb.m_threw) + xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); + + if(rb.m_at & assertType::is_throws_as) + xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); + if(rb.m_at & assertType::is_throws_with) + xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string.c_str()); + if((rb.m_at & assertType::is_normal) && !rb.m_threw) + xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void log_message(const MessageData& mb) override { + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Message") + .writeAttribute("type", failureString(mb.m_severity)) + .writeAttribute("filename", skipPathFromFilename(mb.m_file)) + .writeAttribute("line", line(mb.m_line)); + + xml.scopedElement("Text").writeText(mb.m_string.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void test_case_skipped(const TestCaseData& in) override { + if(opt.no_skipped_summary == false) { + test_case_start_impl(in); + xml.writeAttribute("skipped", "true"); + xml.endElement(); + } + } + }; + + DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); + + void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { + if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == + 0) //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " + << Color::None; + + if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; + } else if((rb.m_at & assertType::is_throws_as) && + (rb.m_at & assertType::is_throws_with)) { //!OCLINT + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string.c_str() + << "\", " << rb.m_exception_type << " ) " << Color::None; + if(rb.m_threw) { + if(!rb.m_failed) { + s << "threw as expected!\n"; + } else { + s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; + } + } else { + s << "did NOT throw at all!\n"; + } + } else if(rb.m_at & + assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " + << rb.m_exception_type << " ) " << Color::None + << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & + assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string.c_str() + << "\" ) " << Color::None + << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan + << rb.m_exception << "\n"; + } else { + s << (rb.m_threw ? "THREW exception: " : + (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); + if(rb.m_threw) + s << rb.m_exception << "\n"; + else + s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; + } + } + + // TODO: + // - log_message() + // - respond to queries + // - honor remaining options + // - more attributes in tags + struct JUnitReporter : public IReporter + { + XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + Timer timer; + std::vector deepestSubcaseStackNames; + + struct JUnitTestCaseData + { + static std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + + std::tm timeInfo; +#ifdef DOCTEST_PLATFORM_WINDOWS + gmtime_s(&timeInfo, &rawtime); +#else // DOCTEST_PLATFORM_WINDOWS + gmtime_r(&rawtime, &timeInfo); +#endif // DOCTEST_PLATFORM_WINDOWS + + char timeStamp[timeStampSize]; + const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; + + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); + return std::string(timeStamp); + } + + struct JUnitTestMessage + { + JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) + : message(_message), type(_type), details(_details) {} + + JUnitTestMessage(const std::string& _message, const std::string& _details) + : message(_message), type(), details(_details) {} + + std::string message, type, details; + }; + + struct JUnitTestCase + { + JUnitTestCase(const std::string& _classname, const std::string& _name) + : classname(_classname), name(_name), time(0), failures() {} + + std::string classname, name; + double time; + std::vector failures, errors; + }; + + void add(const std::string& classname, const std::string& name) { + testcases.emplace_back(classname, name); + } + + void appendSubcaseNamesToLastTestcase(std::vector nameStack) { + for(auto& curr: nameStack) + if(curr.size()) + testcases.back().name += std::string("/") + curr.c_str(); + } + + void addTime(double time) { + if(time < 1e-4) + time = 0; + testcases.back().time = time; + totalSeconds += time; + } + + void addFailure(const std::string& message, const std::string& type, const std::string& details) { + testcases.back().failures.emplace_back(message, type, details); + ++totalFailures; + } + + void addError(const std::string& message, const std::string& details) { + testcases.back().errors.emplace_back(message, details); + ++totalErrors; + } + + std::vector testcases; + double totalSeconds = 0; + int totalErrors = 0, totalFailures = 0; + }; + + JUnitTestCaseData testCaseData; + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc = nullptr; + + JUnitReporter(const ContextOptions& co) + : xml(*co.cout) + , opt(co) {} + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData&) override { + xml.writeDeclaration(); + } + + void test_run_start() override { + xml.writeDeclaration(); + } + + void test_run_end(const TestRunStats& p) override { + // remove .exe extension - mainly to have the same output on UNIX and Windows + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if(binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + xml.startElement("testsuites"); + xml.startElement("testsuite").writeAttribute("name", binary_name) + .writeAttribute("errors", testCaseData.totalErrors) + .writeAttribute("failures", testCaseData.totalFailures) + .writeAttribute("tests", p.numAsserts); + if(opt.no_time_in_output == false) { + xml.writeAttribute("time", testCaseData.totalSeconds); + xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); + } + if(opt.no_version == false) + xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); + + for(const auto& testCase : testCaseData.testcases) { + xml.startElement("testcase") + .writeAttribute("classname", testCase.classname) + .writeAttribute("name", testCase.name); + if(opt.no_time_in_output == false) + xml.writeAttribute("time", testCase.time); + // This is not ideal, but it should be enough to mimic gtest's junit output. + xml.writeAttribute("status", "run"); + + for(const auto& failure : testCase.failures) { + xml.scopedElement("failure") + .writeAttribute("message", failure.message) + .writeAttribute("type", failure.type) + .writeText(failure.details, false); + } + + for(const auto& error : testCase.errors) { + xml.scopedElement("error") + .writeAttribute("message", error.message) + .writeText(error.details); + } + + xml.endElement(); + } + xml.endElement(); + xml.endElement(); + } + + void test_case_start(const TestCaseData& in) override { + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + timer.start(); + } + + void test_case_reenter(const TestCaseData& in) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + + timer.start(); + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + } + + void test_case_end(const CurrentTestCaseStats&) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addError("exception", e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + deepestSubcaseStackNames.push_back(in.m_name); + } + + void subcase_end() override {} + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed) // report only failures & ignore the `success` option + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") + << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; + + fulltext_log_assert_to_stream(os, rb); + log_contexts(os); + testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); + } + + void log_message(const MessageData& mb) override { + if(mb.m_severity & assertType::is_warn) // report only failures + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(mb.m_file) << (opt.gnu_file_line ? ":" : "(") + << line(mb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; + + os << mb.m_string.c_str() << "\n"; + log_contexts(os); + + testCaseData.addFailure(mb.m_string.c_str(), + mb.m_severity & assertType::is_check ? "FAIL_CHECK" : "FAIL", os.str()); + } + + void test_case_skipped(const TestCaseData&) override {} + + void log_contexts(std::ostringstream& s) { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + + s << " logged: "; + for(int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << std::endl; + } + } + } + }; + + DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); + + struct Whitespace + { + int nrSpaces; + explicit Whitespace(int nr) + : nrSpaces(nr) {} + }; + + std::ostream& operator<<(std::ostream& out, const Whitespace& ws) { + if(ws.nrSpaces != 0) + out << std::setw(ws.nrSpaces) << ' '; + return out; + } + + struct ConsoleReporter : public IReporter + { + std::ostream& s; + bool hasLoggedCurrentTestStart; + std::vector subcasesStack; + size_t currentSubcaseLevel; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc; + + ConsoleReporter(const ContextOptions& co) + : s(*co.cout) + , opt(co) {} + + ConsoleReporter(const ContextOptions& co, std::ostream& ostr) + : s(ostr) + , opt(co) {} + + // ========================================================================================= + // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE + // ========================================================================================= + + void separator_to_stream() { + s << Color::Yellow + << "===============================================================================" + "\n"; + } + + const char* getSuccessOrFailString(bool success, assertType::Enum at, + const char* success_str) { + if(success) + return success_str; + return failureString(at); + } + + Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : + (at & assertType::is_warn) ? Color::Yellow : Color::Red; + } + + void successOrFailColoredStringToStream(bool success, assertType::Enum at, + const char* success_str = "SUCCESS") { + s << getSuccessOrFailColor(success, at) + << getSuccessOrFailString(success, at, success_str) << ": "; + } + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + + s << Color::None << " logged: "; + for(int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << "\n"; + } + } + + s << "\n"; + } + + // this was requested to be made virtual so users could override it + virtual void file_line_to_stream(const char* file, int line, + const char* tail = "") { + s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") + << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option + << (opt.gnu_file_line ? ":" : "):") << tail; + } + + void logTestStart() { + if(hasLoggedCurrentTestStart) + return; + + separator_to_stream(); + file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); + if(tc->m_description) + s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; + if(tc->m_test_suite && tc->m_test_suite[0] != '\0') + s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; + if(strncmp(tc->m_name, " Scenario:", 11) != 0) + s << Color::Yellow << "TEST CASE: "; + s << Color::None << tc->m_name << "\n"; + + for(size_t i = 0; i < currentSubcaseLevel; ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + + if(currentSubcaseLevel != subcasesStack.size()) { + s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; + for(size_t i = 0; i < subcasesStack.size(); ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + } + + s << "\n"; + + hasLoggedCurrentTestStart = true; + } + + void printVersion() { + if(opt.no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" + << DOCTEST_VERSION_STR << "\"\n"; + } + + void printIntro() { + if(opt.no_intro == false) { + printVersion(); + s << Color::Cyan << "[doctest] " << Color::None + << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; + } + } + + void printHelp() { + int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); + printVersion(); + // clang-format off + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filters use wildcards for matching strings\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "something passes a filter if any of the strings in a filter matches\n"; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; +#endif + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "Query flags - the program quits after them. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " + << Whitespace(sizePrefixDisplay*0) << "prints this message\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " + << Whitespace(sizePrefixDisplay*1) << "prints the version\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " + << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " + << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " + << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " + << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n"; + // ================================================================================== << 79 + s << Color::Cyan << "[doctest] " << Color::None; + s << "The available / options/filters are:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " + << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " + << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " + << Whitespace(sizePrefixDisplay*1) << "output filename\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " + << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; + s << Whitespace(sizePrefixDisplay*3) << " - [file/suite/name/rand/none]\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " + << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " + << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " + << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " + << Whitespace(sizePrefixDisplay*1) << "stop after failed assertions\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " + << Whitespace(sizePrefixDisplay*1) << "apply filters for the first levels\n"; + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " + << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " + << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " + << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " + << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "m, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "minimal= " + << Whitespace(sizePrefixDisplay*1) << "minimal console output (only failures)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "q, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "quiet= " + << Whitespace(sizePrefixDisplay*1) << "no console output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " + << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " + << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " + << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ni, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-intro= " + << Whitespace(sizePrefixDisplay*1) << "omit the framework intro in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " + << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " + << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " + << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " + << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " + << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " + << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " + << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " + << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n"; + // ================================================================================== << 79 + // clang-format on + + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "for more information visit the project documentation\n\n"; + } + + void printRegisteredReporters() { + printVersion(); + auto printReporters = [this] (const reporterMap& reporters, const char* type) { + if(reporters.size()) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; + for(auto& curr : reporters) + s << "priority: " << std::setw(5) << curr.first.first + << " name: " << curr.first.second << "\n"; + } + }; + printReporters(getListeners(), "listeners"); + printReporters(getReporters(), "reporters"); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + if(opt.version) { + printVersion(); + } else if(opt.help) { + printHelp(); + } else if(opt.list_reporters) { + printRegisteredReporters(); + } else if(opt.count || opt.list_test_cases) { + if(opt.list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None + << "listing all test case names\n"; + separator_to_stream(); + } + + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_name << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + + } else if(opt.list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; + separator_to_stream(); + + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_test_suite << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " + << g_cs->numTestSuitesPassingFilters << "\n"; + } + } + + void test_run_start() override { + if(!opt.minimal) + printIntro(); + } + + void test_run_end(const TestRunStats& p) override { + if(opt.minimal && p.numTestCasesFailed == 0) + return; + + separator_to_stream(); + s << std::dec; + + auto totwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); + auto passwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); + auto failwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1))); + const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; + s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) + << p.numTestCasesPassingFilters << " | " + << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : + Color::Green) + << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" + << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) + << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |"; + if(opt.no_skipped_summary == false) { + const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; + s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped + << " skipped" << Color::None; + } + s << "\n"; + s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth) + << p.numAsserts << " | " + << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) + << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None + << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) + << p.numAssertsFailed << " failed" << Color::None << " |\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) + << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; + } + + void test_case_start(const TestCaseData& in) override { + hasLoggedCurrentTestStart = false; + tc = ∈ + subcasesStack.clear(); + currentSubcaseLevel = 0; + } + + void test_case_reenter(const TestCaseData&) override { + subcasesStack.clear(); + } + + void test_case_end(const CurrentTestCaseStats& st) override { + if(tc->m_no_output) + return; + + // log the preamble of the test case only if there is something + // else to print - something other than that an assert has failed + if(opt.duration || + (st.failure_flags && st.failure_flags != static_cast(TestCaseFailureReason::AssertFailure))) + logTestStart(); + + if(opt.duration) + s << Color::None << std::setprecision(6) << std::fixed << st.seconds + << " s: " << tc->m_name << "\n"; + + if(st.failure_flags & TestCaseFailureReason::Timeout) + s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) + << std::fixed << tc->m_timeout << "!\n"; + + if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { + s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { + s << Color::Yellow << "Failed as expected so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { + s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { + s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures + << " times so marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { + s << Color::Yellow << "Failed exactly " << tc->m_expected_failures + << " times as expected so marking it as not failed!\n"; + } + if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { + s << Color::Red << "Aborting - too many failed asserts!\n"; + } + s << Color::None; // lgtm [cpp/useless-expression] + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + if(tc->m_no_output) + return; + + logTestStart(); + + file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); + successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : + assertType::is_check); + s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") + << Color::Cyan << e.error_string << "\n"; + + int num_stringified_contexts = get_num_stringified_contexts(); + if(num_stringified_contexts) { + auto stringified_contexts = get_stringified_contexts(); + s << Color::None << " logged: "; + for(int i = num_stringified_contexts; i > 0; --i) { + s << (i == num_stringified_contexts ? "" : " ") + << stringified_contexts[i - 1] << "\n"; + } + } + s << "\n" << Color::None; + } + + void subcase_start(const SubcaseSignature& subc) override { + subcasesStack.push_back(subc); + ++currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void subcase_end() override { + --currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void log_assert(const AssertData& rb) override { + if((!rb.m_failed && !opt.success) || tc->m_no_output) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + logTestStart(); + + file_line_to_stream(rb.m_file, rb.m_line, " "); + successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); + + fulltext_log_assert_to_stream(s, rb); + + log_contexts(); + } + + void log_message(const MessageData& mb) override { + if(tc->m_no_output) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + logTestStart(); + + file_line_to_stream(mb.m_file, mb.m_line, " "); + s << getSuccessOrFailColor(false, mb.m_severity) + << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, + "MESSAGE") << ": "; + s << Color::None << mb.m_string << "\n"; + log_contexts(); + } + + void test_case_skipped(const TestCaseData&) override {} + }; + + DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); + +#ifdef DOCTEST_PLATFORM_WINDOWS + struct DebugOutputWindowReporter : public ConsoleReporter + { + DOCTEST_THREAD_LOCAL static std::ostringstream oss; + + DebugOutputWindowReporter(const ContextOptions& co) + : ConsoleReporter(co, oss) {} + +#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ + void func(type arg) override { \ + bool with_col = g_no_colors; \ + g_no_colors = false; \ + ConsoleReporter::func(arg); \ + if(oss.tellp() != std::streampos{}) { \ + DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ + oss.str(""); \ + } \ + g_no_colors = with_col; \ + } + + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in) + }; + + DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; +#endif // DOCTEST_PLATFORM_WINDOWS + + // the implementation of parseOption() + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { + // going from the end to the beginning and stopping on the first occurrence from the end + for(int i = argc; i > 0; --i) { + auto index = i - 1; + auto temp = std::strstr(argv[index], pattern); + if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue + // eliminate matches in which the chars before the option are not '-' + bool noBadCharsFound = true; + auto curr = argv[index]; + while(curr != temp) { + if(*curr++ != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[index][0] == '-') { + if(value) { + // parsing the value of an option + temp += strlen(pattern); + const unsigned len = strlen(temp); + if(len) { + *value = temp; + return true; + } + } else { + // just a flag - no value + return true; + } + } + } + } + return false; + } + + // parses an option and returns the string after the '=' character + bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, + const String& defaultVal = String()) { + if(value) + *value = defaultVal; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + // offset (normally 3 for "dt-") to skip prefix + if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) + return true; +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, value); + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { + return parseOption(argc, argv, pattern); + } + + // parses a comma separated list of words after a pattern in one of the arguments in argv + bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, + std::vector& res) { + String filtersString; + if(parseOption(argc, argv, pattern, &filtersString)) { + // tokenize with "," as a separator, unless escaped with backslash + std::ostringstream s; + auto flush = [&s, &res]() { + auto string = s.str(); + if(string.size() > 0) { + res.push_back(string.c_str()); + } + s.str(""); + }; + + bool seenBackslash = false; + const char* current = filtersString.c_str(); + const char* end = current + strlen(current); + while(current != end) { + char character = *current++; + if(seenBackslash) { + seenBackslash = false; + if(character == ',' || character == '\\') { + s.put(character); + continue; + } + s.put('\\'); + } + if(character == '\\') { + seenBackslash = true; + } else if(character == ',') { + flush(); + } else { + s.put(character); + } + } + + if(seenBackslash) { + s.put('\\'); + } + flush(); + return true; + } + return false; + } + + enum optionType + { + option_bool, + option_int + }; + + // parses an int/bool option from the command line + bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, + int& res) { + String parsedValue; + if(!parseOption(argc, argv, pattern, &parsedValue)) + return false; + + if(type) { + // integer + // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse... + int theInt = std::atoi(parsedValue.c_str()); + if (theInt != 0) { + res = theInt; //!OCLINT parameter reassignment + return true; + } + } else { + // boolean + const char positive[][5] = { "1", "true", "on", "yes" }; // 5 - strlen("true") + 1 + const char negative[][6] = { "0", "false", "off", "no" }; // 6 - strlen("false") + 1 + + // if the value matches any of the positive/negative possibilities + for (unsigned i = 0; i < 4; i++) { + if (parsedValue.compare(positive[i], true) == 0) { + res = 1; //!OCLINT parameter reassignment + return true; + } + if (parsedValue.compare(negative[i], true) == 0) { + res = 0; //!OCLINT parameter reassignment + return true; + } + } + } + return false; + } +} // namespace + +Context::Context(int argc, const char* const* argv) + : p(new detail::ContextState) { + parseArgs(argc, argv, true); + if(argc) + p->binary_name = argv[0]; +} + +Context::~Context() { + if(g_cs == p) + g_cs = nullptr; + delete p; +} + +void Context::applyCommandLine(int argc, const char* const* argv) { + parseArgs(argc, argv); + if(argc) + p->binary_name = argv[0]; +} + +// parses args +void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { + using namespace detail; + + // clang-format off + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); + // clang-format on + + int intRes = 0; + String strRes; + +#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ + p->var = static_cast(intRes); \ + else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ + p->var = true; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ + p->var = intRes; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ + if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ + parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \ + withDefaults) \ + p->var = strRes + + // clang-format off + DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); + DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); + DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); + DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); + + DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); + DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("minimal", "m", minimal, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("quiet", "q", quiet, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-intro", "ni", no_intro, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); + // clang-format on + + if(withDefaults) { + p->help = false; + p->version = false; + p->count = false; + p->list_test_cases = false; + p->list_test_suites = false; + p->list_reporters = false; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { + p->help = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { + p->version = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { + p->count = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { + p->list_test_cases = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { + p->list_test_suites = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { + p->list_reporters = true; + p->exit = true; + } +} + +// allows the user to add procedurally to the filters from the command line +void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } + +// allows the user to clear all filters from the command line +void Context::clearFilters() { + for(auto& curr : p->filters) + curr.clear(); +} + +// allows the user to override procedurally the bool options from the command line +void Context::setOption(const char* option, bool value) { + setOption(option, value ? "true" : "false"); +} + +// allows the user to override procedurally the int options from the command line +void Context::setOption(const char* option, int value) { + setOption(option, toString(value).c_str()); +} + +// allows the user to override procedurally the string options from the command line +void Context::setOption(const char* option, const char* value) { + auto argv = String("-") + option + "=" + value; + auto lvalue = argv.c_str(); + parseArgs(1, &lvalue); +} + +// users should query this in their main() and exit the program if true +bool Context::shouldExit() { return p->exit; } + +void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; } + +void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } + +void Context::setCout(std::ostream* out) { p->cout = out; } + +static class DiscardOStream : public std::ostream +{ +private: + class : public std::streambuf + { + private: + // allowing some buffering decreases the amount of calls to overflow + char buf[1024]; + + protected: + std::streamsize xsputn(const char_type*, std::streamsize count) override { return count; } + + int_type overflow(int_type ch) override { + setp(std::begin(buf), std::end(buf)); + return traits_type::not_eof(ch); + } + } discardBuf; + +public: + DiscardOStream() + : std::ostream(&discardBuf) {} +} discardOut; + +// the main function that does all the filtering and test running +int Context::run() { + using namespace detail; + + // save the old context state in case such was setup - for using asserts out of a testing context + auto old_cs = g_cs; + // this is the current contest + g_cs = p; + is_running_in_test = true; + + g_no_colors = p->no_colors; + p->resetRunData(); + + std::fstream fstr; + if(p->cout == nullptr) { + if(p->quiet) { + p->cout = &discardOut; + } else if(p->out.size()) { + // to a file if specified + fstr.open(p->out.c_str(), std::fstream::out); + p->cout = &fstr; + } else { +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + // stdout by default + p->cout = &std::cout; +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + return EXIT_FAILURE; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + } + } + + FatalConditionHandler::allocateAltStackMem(); + + auto cleanup_and_return = [&]() { + FatalConditionHandler::freeAltStackMem(); + + if(fstr.is_open()) + fstr.close(); + + // restore context + g_cs = old_cs; + is_running_in_test = false; + + // we have to free the reporters which were allocated when the run started + for(auto& curr : p->reporters_currently_used) + delete curr; + p->reporters_currently_used.clear(); + + if(p->numTestCasesFailed && !p->no_exitcode) + return EXIT_FAILURE; + return EXIT_SUCCESS; + }; + + // setup default reporter if none is given through the command line + if(p->filters[8].empty()) + p->filters[8].push_back("console"); + + // check to see if any of the registered reporters has been selected + for(auto& curr : getReporters()) { + if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) + p->reporters_currently_used.push_back(curr.second(*g_cs)); + } + + // TODO: check if there is nothing in reporters_currently_used + + // prepend all listeners + for(auto& curr : getListeners()) + p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); + +#ifdef DOCTEST_PLATFORM_WINDOWS + if(isDebuggerActive() && p->no_debug_output == false) + p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); +#endif // DOCTEST_PLATFORM_WINDOWS + + // handle version, help and no_run + if(p->no_run || p->version || p->help || p->list_reporters) { + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); + + return cleanup_and_return(); + } + + std::vector testArray; + for(auto& curr : getRegisteredTests()) + testArray.push_back(&curr); + p->numTestCases = testArray.size(); + + // sort the collected records + if(!testArray.empty()) { + if(p->order_by.compare("file", true) == 0) { + std::sort(testArray.begin(), testArray.end(), fileOrderComparator); + } else if(p->order_by.compare("suite", true) == 0) { + std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); + } else if(p->order_by.compare("name", true) == 0) { + std::sort(testArray.begin(), testArray.end(), nameOrderComparator); + } else if(p->order_by.compare("rand", true) == 0) { + std::srand(p->rand_seed); + + // random_shuffle implementation + const auto first = &testArray[0]; + for(size_t i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = std::rand() % (i + 1); + + const auto temp = first[i]; + + first[i] = first[idxToSwap]; + first[idxToSwap] = temp; + } + } else if(p->order_by.compare("none", true) == 0) { + // means no sorting - beneficial for death tests which call into the executable + // with a specific test case in mind - we don't want to slow down the startup times + } + } + + std::set testSuitesPassingFilt; + + bool query_mode = p->count || p->list_test_cases || p->list_test_suites; + std::vector queryResults; + + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); + + // invoke the registered functions if they match the filter criteria (or just count them) + for(auto& curr : testArray) { + const auto& tc = *curr; + + bool skip_me = false; + if(tc.m_skip && !p->no_skip) + skip_me = true; + + if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) + skip_me = true; + + if(!skip_me) + p->numTestCasesPassingFilters++; + + // skip the test if it is not in the execution range + if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || + (p->first > p->numTestCasesPassingFilters)) + skip_me = true; + + if(skip_me) { + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); + continue; + } + + // do not execute the test if we are to only count the number of filter passing tests + if(p->count) + continue; + + // print the name of the test and don't execute it + if(p->list_test_cases) { + queryResults.push_back(&tc); + continue; + } + + // print the name of the test suite if not done already and don't execute it + if(p->list_test_suites) { + if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { + queryResults.push_back(&tc); + testSuitesPassingFilt.insert(tc.m_test_suite); + p->numTestSuitesPassingFilters++; + } + continue; + } + + // execute the test if it passes all the filtering + { + p->currentTest = &tc; + + p->failure_flags = TestCaseFailureReason::None; + p->seconds = 0; + + // reset atomic counters + p->numAssertsFailedCurrentTest_atomic = 0; + p->numAssertsCurrentTest_atomic = 0; + + p->fullyTraversedSubcases.clear(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); + + p->timer.start(); + + bool run_test = true; + + do { + // reset some of the fields for subcases (except for the set of fully passed ones) + p->reachedLeaf = false; + // May not be empty if previous subcase exited via exception. + p->subcaseStack.clear(); + p->currentSubcaseDepth = 0; + + p->shouldLogCurrentException = true; + + // reset stuff for logging with INFO() + p->stringifiedContexts.clear(); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method) +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable + FatalConditionHandler fatalConditionHandler; // Handle signals + // execute the test + tc.m_test(); + fatalConditionHandler.reset(); +DOCTEST_MSVC_SUPPRESS_WARNING_POP +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + } catch(const TestFailureException&) { + p->failure_flags |= TestCaseFailureReason::AssertFailure; + } catch(...) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, + {translateActiveException(), false}); + p->failure_flags |= TestCaseFailureReason::Exception; + } +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + + // exit this loop if enough assertions have failed - even if there are more subcases + if(p->abort_after > 0 && + p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { + run_test = false; + p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; + } + + if(!p->nextSubcaseStack.empty() && run_test) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); + if(p->nextSubcaseStack.empty()) + run_test = false; + } while(run_test); + + p->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + p->currentTest = nullptr; + + // stop executing tests if enough assertions have failed + if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) + break; + } + } + + if(!query_mode) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } else { + QueryData qdata; + qdata.run_stats = g_cs; + qdata.data = queryResults.data(); + qdata.num_data = unsigned(queryResults.size()); + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); + } + + return cleanup_and_return(); +} + +DOCTEST_DEFINE_INTERFACE(IReporter) + +int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } +const IContextScope* const* IReporter::get_active_contexts() { + return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; +} + +int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } +const String* IReporter::get_stringified_contexts() { + return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; +} + +namespace detail { + void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { + if(isReporter) + getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + else + getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + } +} // namespace detail + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 +int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#endif // DOCTEST_LIBRARY_IMPLEMENTATION +#endif // DOCTEST_CONFIG_IMPLEMENT + +#ifdef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#endif // DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN + +#ifdef DOCTEST_UNDEF_NOMINMAX +#undef NOMINMAX +#undef DOCTEST_UNDEF_NOMINMAX +#endif // DOCTEST_UNDEF_NOMINMAX diff --git a/3rdparty/libbacktrace/CMakeLists.txt b/3rdparty/libbacktrace/CMakeLists.txt deleted file mode 100644 index b86ba5d9..00000000 --- a/3rdparty/libbacktrace/CMakeLists.txt +++ /dev/null @@ -1,192 +0,0 @@ -# based on: https://github.com/ValveSoftware/vogl/blob/master/src/libbacktrace/CMakeLists.txt -# -# CMakeLists.txt -- libbacktrace CMake build script -# Contributed by Alexander Monakov, ISP RAS -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) The name of the author may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. */ - -cmake_minimum_required (VERSION 2.8) - -project (libbacktrace) - -set (BACKTRACE_SUPPORTED 1) - -add_definitions("-DHAVE_STDINT_H") - -include (CheckSymbolExists) -if (true) - # When unwind.h is in /usr/local/include, check_symbol_exists() is failing. But - # these functions are in the Linux Standard Base Core Spec and should just exist - # for Linux, yes? I'm assuming that's the case for now and using them. - # (Otherwise stack tracing won't work anyway). - set (HAVE_BACKTRACE 1) - set (HAVE_GETIPINFO 1) -else() - check_symbol_exists (_Unwind_Backtrace unwind.h HAVE_BACKTRACE) - check_symbol_exists (_Unwind_GetIPInfo unwind.h HAVE_GETIPINFO) -endif() - -if (HAVE_BACKTRACE) - set (BACKTRACE_FILE backtrace.c simple.c) -else () - message(FATAL_ERROR "Could not find unwind.h, install the libunwind development package.") -endif () - -include (CheckCCompilerFlag) -check_c_compiler_flag ("-funwind-tables" FLAG_UNWIND_TABLES) -if (FLAG_UNWIND_TABLES) - add_definitions ("-funwind-tables") -endif () - -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions("-D_DEBUG -DDEBUG") -endif() - -# Adjust warnings -if (CMAKE_COMPILER_IS_GNUCC) - add_definitions ("-Wno-switch -Wno-enum-compare") -endif () - -# Add these compiler options to match how voglcore and voglcommon are compiled, and to get libbacktrace compiling with gcc. -# -fno-strict-aliasing is particularly important if voglcore is called, and -fvisibility=hidden must be used otherwide symbols from this lib could be made visible in libvogltrace. -add_definitions ("-g -fno-omit-frame-pointer -fno-strict-aliasing -fno-math-errno -fvisibility=hidden") -SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -g -DNDEBUG") - -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") - if ( NOT BUILD_X64 ) - # Fix startup crash in dlopen_notify_callback (called indirectly from our dlopen() function) when tracing glxspheres on my AMD dev box (x86 release only) - #add_definitions ("-mstack-alignment=8") - endif() -endif() - -# clang doesn't print colored diagnostics when invoked from Ninja -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") - if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja") - add_definitions ("-fcolor-diagnostics") - endif() -endif() - -check_c_source_compiles ( - "int i; - int main() { - __sync_bool_compare_and_swap (&i, i, i); - __sync_lock_test_and_set (&i, 1); - __sync_lock_release (&i);}" - HAVE_SYNC_FUNCTIONS) - -check_c_source_compiles ( - "int i; - int main() { - __atomic_load_n (&i, __ATOMIC_ACQUIRE); - __atomic_store_n (&i, i, __ATOMIC_RELEASE);}" - HAVE_ATOMIC_FUNCTIONS) - -if (HAVE_SYNC_FUNCTIONS OR HAVE_ATOMIC_FUNCTIONS) - set (BACKTRACE_SUPPORTS_THREADS 1) -else () - set (BACKTRACE_SUPPORTS_THREADS 0) -endif () - -include(CMakeDetermineCompilerId) -if (CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") - set (FORMAT_FILE elf.c dwarf.c) - math (EXPR BACKTRACE_ELF_SIZE 8*${CMAKE_C_SIZEOF_DATA_PTR}) -else () - message(FATAL_ERROR "Unknown executable format \"${CMAKE_EXECUTABLE_FORMAT}\", currently only ELF is supported.") -endif () - -check_symbol_exists (mmap sys/mman.h HAVE_MMAP) -check_symbol_exists(lstat sys/stat.h HAVE_LSTAT) -check_symbol_exists(readlink unistd.h HAVE_READLINK) - -# NOTE: For the use-case of heaptrack, we want to use malloc for allocating -# the tiny fragments required for reading a backtrace as we are doing this -# in a separate process, outside of a potential signal handler -# This has a tremendous impact on the performance when analyzing the DWARF -# symbols of a large binary, such as clang++ or webkit. -set (ALLOC_FILE alloc.c) -set (BACKTRACE_USES_MALLOC 1) - -if (HAVE_MMAP) - set (VIEW_FILE mmapio.c) - check_symbol_exists (MAP_ANONYMOUS sys/mman.h HAVE_MMAP_ANONYMOUS) - check_symbol_exists (MAP_ANON sys/mman.h HAVE_MMAP_ANON) -else () - set (VIEW_FILE read.c) -endif () - -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions("-D_DEBUG -DDEBUG") -endif() -add_definitions (-D_GNU_SOURCE) -set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE) -check_symbol_exists (dl_iterate_phdr link.h HAVE_DL_ITERATE_PHDR) - -include (CheckFunctionExists) -check_function_exists (fcntl HAVE_FCNTL) - -check_function_exists (strnlen HAVE_DECL_STRNLEN) - -check_function_exists (getexecname HAVE_GETEXECNAME) - -include (CheckIncludeFile) -find_path(DWARF_INCLUDE_DIR dwarf.h - PATH_SUFFIXES libdwarf) -if (NOT DWARF_INCLUDE_DIR) - message(FATAL_ERROR "Could not find dwarf.h, try installing the dwarf or elfutils development package.") -endif () -include_directories(${DWARF_INCLUDE_DIR}) - -configure_file (backtrace-supported.h.in backtrace-supported.h) - -configure_file (config.h.in.cmake config.h) - -include_directories (BEFORE - ${CMAKE_CURRENT_BINARY_DIR} -) -include_directories ( - auxincl -) - -add_library (backtrace STATIC - ${BACKTRACE_FILE} - ${FORMAT_FILE} - ${VIEW_FILE} - ${ALLOC_FILE} - atomic.c - fileline.c - posix.c - print.c - state.c - sort.c -) - -set_target_properties (backtrace PROPERTIES - COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}" -) diff --git a/3rdparty/libbacktrace/ChangeLog b/3rdparty/libbacktrace/ChangeLog deleted file mode 100644 index 35af7e5c..00000000 --- a/3rdparty/libbacktrace/ChangeLog +++ /dev/null @@ -1,827 +0,0 @@ -2017-11-17 Igor Tsimbalist - - * configure.ac: Add CET_FLAGS to EXTRA_FLAGS. - * aclocal.m4: Regenerate. - * Makefile.in: Likewise. - * configure: Likewise. - -2017-10-06 Ian Lance Taylor - - * ztest.c (test_large): Pass unsigned long *, not size_t *, to - zlib uncompress function. - -2017-10-05 Ian Lance Taylor - - * elf.c (elf_zlib_fetch): Change pval argument to uint64_t *. - Read a four byte integer. - (elf_zlib_inflate): Change val to uint64_t. Align pin to a 32-bit - boundary before ever calling elf_zlib_fetch. - * ztest.c (test_large): Simplify print statements a bit. - -2017-10-02 Ian Lance Taylor - - * ztest.c: #include . - (TEST_TIMING): Don't define, don't test. - (xclock_gettime, xclockid_t): Define if !HAVE_CLOCK_GETTIME. - (clockid_t, clock_gettime, CLOCK_REALTIME): Likewise. - (ZLIB_CLOCK_GETTIME_ARG): Define. - * configure.ac: Change clock_gettime_link to CLOCK_GETTIME_LINK. - * Makefile.am: Likewise. - * configure, Makefile.in: Rebuild. - -2017-10-02 Thomas Schwinge - - PR other/67165 - * Makefile.am: Append the content of clock_gettime_link to - ztest_LDADD. - * configure.ac: Test for the case that clock_gettime is in librt. - * Makefile.in: Regenerate. - * configure: Likewise. - - PR other/67165 - * configure.ac: Check for clock_gettime. - * config.h.in: Regenerate. - * configure: Likewise. - * ztest.c (average_time, test_large): Conditionalize test timing - on clock_gettime availability. - -2017-09-29 Tony Reix - - * xcoff.c: Initial support for DWARF debug sections in XCOFF. - (STYP_DWARF, SSUBTYP_DW*): Define. - (enum dwarf_section): Define. - (struct dwsect_info): Define. - (xcoff_add): Look for DWARF sections, pass them to - backtrace_dwarf_add. - -2017-09-28 Ian Lance Taylor - - PR other/67165 - * elf.c (__builtin_prefetch): Define if not __GNUC__. - (unlikely): Define. - (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define. - (b_elf_chdr): Define type. - (enum debug_section): Add ZDEBUG_xxx values. - (debug_section_names): Add names for new sections. - (struct debug_section_info): Add compressed field. - (elf_zlib_failed, elf_zlib_fetch): New static functions. - (HUFFMAN_TABLE_SIZE, HUFFMAN_VALUE_MASK): Define. - (HUFFMAN_BITS_SHIFT, HUFFMAN_BITS_MASK): Define. - (HUFFMAN_SECONDARY_SHIFT): Define. - (ZDEBUG_TABLE_SIZE): Define. - (ZDEBUG_TABLE_CODELEN_OFFSET, ZDEBUG_TABLE_WORK_OFFSET): Define. - (final_next_secondary): New static variable if - BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE. - (elf_zlib_inflate_table): New static function. - (BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE): If define, define main - function to produce fixed Huffman table. - (elf_zlib_default_table): New static variable. - (elf_zlib_inflate): New static function. - (elf_zlib_verify_checksum): Likewise. - (elf_zlib_inflate_and_verify): Likewise. - (elf_uncompress_zdebug): Likewise. - (elf_uncompress_chdr): Likewise. - (backtrace_uncompress_zdebug): New extern function. - (elf_add): Look for .zdebug sections and SHF_COMPRESSED debug - sections, and uncompress them. - * internal.h (backtrace_compress_zdebug): Declare. - * ztest.c: New file. - * configure.ac: Check for -lz and check whether the linker - supports --compress-debug-sections. - * Makefile.am (ztest_SOURCES): New variable. - (ztest_CFLAGS, ztest_LDADD): New variables. - (check_PROGRAMS): Add ztest. - (ctestg_SOURCES): New variable. - (ctestg_CFLAGS, ctestg_LDFLAGS, ctestg_LDADD): New variables. - (ctesta_SOURCES): New variable. - (ctesta_CFLAGS, ctesta_LDFLAGS, ctesta_LDADD): New variables. - (check_PROGRAMS): Add ctestg and ctesta. - * configure, config.h.in, Makefile.in: Rebuild. - -2017-09-22 Ian Lance Taylor - - PR sanitizer/77631 - * configure.ac: Check for lstat and readlink. - * elf.c (lstat, readlink): Provide dummy versions if real versions - are not available. - * configure, config.h.in: Rebuild. - -2017-09-21 Ian Lance Taylor - - PR go/82284 - * elf.c (backtrace_initialize): Set pd.exe_filename. - -2017-09-20 Ian Lance Taylor - Denis Khalikov - - PR sanitizer/77631 - Support for external debug info. - * elf.c: Include , , . - (S_ISLNK): Define if not defined. - (xstrnlen): Define if strnlen is not available. - (b_elf_note): Define type. - (NT_GNU_BUILD_ID): Define macro. - (elf_crc32, elf_crc32_file): New static functions. - (elf_is_symlink, elf_readlink): New static functions. - (elf_open_debugfile_by_buildid): New static function. - (elf_try_debugfile): New static function. - (elf_find_debugfile_by_debuglink): New static function. - (elf_open_debugfile_by_debuglink): New static function. - (elf_add): Add filename and debuginfo parameters. Adjust all - callers. Look for external debug info notes, and try to fetch - debug info from external file. - (struct phdr_data): Add exe_filename field. - (phdr_callback): Pass filename to elf_add. - (backtrace_initialize): Add filename parameter. - * internal.h (backtrace_initialize): Add filename parameter. - * fileline.c (fileline_initialize): Pass filename to - backtrace_initialize. - * pecoff.c (fileline_initialize): Add unused filename parameter. - * unknown.c (fileline_initialize): Likewise. - * xcoff.c (fileline_initialize): Likewise. - * configure.ac: Check for objcopy --add-gnu-debuglink. - * Makefile.am (dtest): New test target. - * configure, Makefile.in: Rebuild. - -2017-09-12 Steve Ellcey - - PR other/81096 - * Makefile.am (ttest_CFLAGS): Add $(AM_CFLAGS) - * Makefile.in: Regenerate. - -2017-09-12 Steve Ellcey - - PR other/81096 - * libbacktrace/Makefile.in - (HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS): Add $(AM_CFLAGS) - -2017-08-02 David Edelsohn - - PR bootstrap/81638 - * xcoff.c (xcoff_process_linenos): Initialize incl to NULL. - -2017-07-28 Tony Reix - - * xcoff.c: Don't leak a file descriptor if an archive is malformed. - -2017-07-28 Rainer Orth - - * fileline.c (fileline_initialize): Print pid_t as long. - -2017-07-26 Tony Reix - - * configure.ac: Check for XCOFF32/XCOFF64. Check for loadquery. - * filetype.awk: Separate AIX XCOFF32 and XCOFF64. - * xcoff.c: Add support for AIX XCOFF32 and XCOFF64 formats. - * configure, config.h.in: Regenerate. - -2017-07-21 Tony Reix - - * filetype.awk: Add AIX XCOFF type detection. - * configure.ac: Recognize xcoff format. - * Makefile.am (FORMAT_FILES): Add xcoff.c. - * fileline.c: Include . - (fileline_initialize): Add case for AIX procfs. - * xcoff.c: New file. - * configure, Makefile.in: Rebuild. - -2017-06-21 Richard Biener - - * configure.ac: Add AC_SYS_LARGEFILE. - * config.h.in: Regenerate. - * configure: Likewise. - -2017-06-11 Ian Lance Taylor - - * elf.c (backtrace_initialize): Always set *fileline_fn. - * ttest.c: New file. - * btest.c: Move support functions into testlib.c. Change calls to - check to pass file name. - * testlib.c: New file, copied from (part of) btest.c. - * testlib.h: New file, declarations for testlib.c. - * edtest.c: Use testlib.h and testlib.c. - * configure.ac: Test for -pthread, set HAVE_PTHREAD conditional. - * Makefile.am (btest_SOURCES): Add testlib.c. - (edtest_SOURCES): Likewise. - (CHECK_PROGRAMS): Add ttest if HAVE_PTHREAD. - (ttest_SOURCES, ttest_CFLAGS, ttest_LDADD): Define. - * configure, Makefile.in: Rebuild. - -2017-05-19 Than McIntosh - - * dwarf.c (free_line_header): Don't free dirs if dirs_count == 0. - (read_line_header): Don't allocate dirs if dirs_count == 0. - * edtest.c: New file. - * edtest2.c: New file. - * Makefile.am (edtest_SOURCES, edtest_LDADD): Define. - (check_PROGRAMS): Add edtest. - (edtest2_build.c, gen_edtest2_build): New targets. - * Makefile.in: Rebuild. - -2017-03-08 Sam Thursfield - - * btest.c (test5): Replace #ifdef guard with 'unused' attribute - to fix compile warning when BACKTRACE_SUPPORTED isn't defined. - -2017-01-01 Jakub Jelinek - - Update copyright years. - -2016-11-15 Matthias Klose - - * configure: Regenerate. - -2016-09-11 Carlos Liam - - * all: Remove meaningless trailing whitespace. - -2016-05-18 Uros Bizjak - - PR target/71161 - * elf.c (phdr_callback) [__i386__]: Add - __attribute__((__force_align_arg_pointer__)). - -2016-03-02 Maxim Ostapenko - - * elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to - avoid possible crash. - (elf_add): Don't set *fileline_fn to elf_nodebug value in case of - missing debug info anymore. - -2016-02-06 John David Anglin - - * mmap.c (MAP_FAILED): Define if not defined. - -2016-01-04 Jakub Jelinek - - Update copyright years. - -2015-12-18 Andris Pavenis - - * configure.ac: Specify that DJGPP do not have mmap - even when sys/mman.h exists. - * configure: Regenerate - -2015-12-09 John David Anglin - - PR libgfortran/68115 - * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. - * configure: Regenerate. - * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call - to void. - -2015-09-17 Ian Lance Taylor - - * posix.c (backtrace_open): Cast second argument of open() to int. - -2015-09-11 Ian Lance Taylor - - * Makefile.am (backtrace.lo): Depend on internal.h. - (sort.lo, stest.lo): Add explicit dependencies. - * Makefile.in: Rebuild. - -2015-09-09 Hans-Peter Nilsson - - * backtrace.c: #include . - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * backtrace.c: #include "internal.h". - (struct backtrace_data): Add can_alloc field. - (unwind): If can_alloc is false, don't try to get file/line - information. - (backtrace_full): Set can_alloc field in bdata. - * alloc.c (backtrace_alloc): Don't call error_callback if it is - NULL. - * mmap.c (backtrace_alloc): Likewise. - * internal.h: Update comments for backtrace_alloc and - backtrace_free. - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * mmap.c (backtrace_alloc): Correct test for mmap failure. - -2015-08-31 Ulrich Weigand - - * configure.ac: For spu-*-* targets, set have_fcntl to no. - * configure: Regenerate. - -2015-08-27 Ulrich Weigand - - * configure.ac: Remove [disable-shared] argument to LT_INIT. - Remove setting PIC_FLAG when building as target library. - * configure: Regenerate. - -2015-08-26 Hans-Peter Nilsson - - * configure.ac: Only compile with -fPIC if the target - supports it. - * configure: Regenerate. - -2015-08-24 Ulrich Weigand - - * configure.ac: Set have_mmap to no on spu-*-* targets. - * configure: Regenerate. - -2015-08-13 Ian Lance Taylor - - * dwarf.c (read_function_entry): Add vec_inlined parameter. - Change all callers. - -2015-06-11 Martin Sebor - - PR sanitizer/65479 - * dwarf.c (struct line): Add new field idx. - (line_compare): Use it. - (add_line): Set it. - (read_line_info): Reset it. - -2015-05-29 Tristan Gingold - - * pecoff.c: New file. - * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. - * Makefile.in: Regenerate. - * filetype.awk: Detect pecoff. - * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. - Add pecoff. - * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is - true. - * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. - * configure: Regenerate. - * pecoff.c: New file. - -2015-05-13 Michael Haubenwallner - - * Makefile.in: Regenerated with automake-1.11.6. - * aclocal.m4: Likewise. - * configure: Likewise. - -2015-01-24 Matthias Klose - - * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. - * configure: Regenerate. - -2015-01-05 Jakub Jelinek - - Update copyright years. - -2014-11-21 H.J. Lu - - PR bootstrap/63784 - * configure: Regenerated. - -2014-11-11 David Malcolm - - * ChangeLog.jit: New. - -2014-11-11 Francois-Xavier Coudert - - PR target/63610 - * configure: Regenerate. - -2014-10-23 Ian Lance Taylor - - * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: - Fix to return void *. - -2014-05-08 Ian Lance Taylor - - * mmap.c (backtrace_free): If freeing a large aligned block of - memory, call munmap rather than holding onto it. - (backtrace_vector_grow): When growing a vector, double the number - of pages requested. When releasing the old version of a grown - vector, pass the correct size to backtrace_free. - -2014-03-07 Ian Lance Taylor - - * sort.c (backtrace_qsort): Use middle element as pivot. - -2014-03-06 Ian Lance Taylor - - * sort.c: New file. - * stest.c: New file. - * internal.h (backtrace_qsort): Declare. - * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. - (read_line_info, read_function_entry): Likewise. - (read_function_info, build_dwarf_data): Likewise. - * elf.c (elf_initialize_syminfo): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. - (stest_SOURCES, stest_LDADD): Define. - (check_PROGRAMS): Add stest. - -2014-02-07 Misty De Meo - - PR target/58710 - * configure.ac: Use AC_LINK_IFELSE in check for - _Unwind_GetIPInfo. - * configure: Regenerate. - -2014-01-02 Richard Sandiford - - Update copyright years - -2013-12-06 Jakub Jelinek - - * elf.c (ET_DYN): Undefine and define again. - (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, - return early -1 without closing the descriptor. - (struct phdr_data): Add exe_descriptor. - (phdr_callback): If pd->exe_descriptor is not -1, for very first - call if dlpi_name is NULL just call elf_add with the exe_descriptor, - otherwise backtrace_close the exe_descriptor if not -1. Adjust - call to elf_add. - (backtrace_initialize): Adjust call to elf_add. If it returns - -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. - -2013-12-05 Ian Lance Taylor - - * alloc.c (backtrace_vector_finish): Add error_callback and data - parameters. Call backtrace_vector_release. Return address base. - * mmap.c (backtrace_vector_finish): Add error_callback and data - parameters. Return address base. - * dwarf.c (read_function_info): Get new address base from - backtrace_vector_finish. - * internal.h (backtrace_vector_finish): Update declaration. - -2013-11-27 Ian Lance Taylor - - * dwarf.c (find_address_ranges): New static function, broken out - of build_address_map. - (build_address_map): Call it. - * btest.c (check): Check for missing filename or function, rather - than crashing. - (f3): Check that enough frames were returned. - -2013-11-19 Jakub Jelinek - - * backtrace.h (backtrace_syminfo_callback): Add symsize argument. - * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as - last argument. - * btest.c (struct symdata): Add size field. - (callback_three): Add symsize argument. Copy it to the data->size - field. - (f23): Set symdata.size to 0. - (test5): Likewise. If sizeof (int) > 1, lookup address of - ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size - values. - - * atomic.c: Include sys/types.h. - -2013-11-18 Ian Lance Taylor - - * configure.ac: Check for support of __atomic extensions. - * internal.h: Declare or #define atomic functions for use in - backtrace code. - * atomic.c: New file. - * dwarf.c (dwarf_lookup_pc): Use atomic functions. - (dwarf_fileline, backtrace_dwarf_add): Likewise. - * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. - (backtrace_initialize): Likewise. - * fileline.c (fileline_initialize): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. - * configure, config.h.in, Makefile.in: Rebuild. - -2013-11-18 Jakub Jelinek - - * elf.c (SHN_UNDEF): Define. - (elf_initialize_syminfo): Add base_address argument. Ignore symbols - with st_shndx == SHN_UNDEF. Add base_address to address fields. - (elf_add): Adjust caller. - - * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. - -2013-11-16 Ian Lance Taylor - - * backtrace.h (backtrace_create_state): Correct comment about - threading. - -2013-11-15 Ian Lance Taylor - - * backtrace.h (backtrace_syminfo): Update comment and parameter - name to take any address, not just a PC value. - * elf.c (STT_OBJECT): Define. - (elf_nosyms): Rename parameter pc to addr. - (elf_symbol_search): Rename local variable pc to addr. - (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. - (elf_syminfo): Rename parameter pc to addr. - * btest.c (global): New global variable. - (test5): New test. - (main): Call test5. - -2013-10-17 Ian Lance Taylor - - * elf.c (elf_add): Don't get the wrong offsets if a debug section - is missing. - -2013-10-15 David Malcolm - - * configure.ac: Add --enable-host-shared, setting up - pre-existing PIC_FLAG variable within Makefile.am et al. - * configure: Regenerate. - -2013-09-20 Alan Modra - - * configure: Regenerate. - -2013-07-23 Alexander Monakov - - * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. - -2013-07-23 Alexander Monakov - - * elf.c (backtrace_initialize): Pass elf_fileline_fn to - dl_iterate_phdr callbacks. - -2013-03-25 Ian Lance Taylor - - * alloc.c: #include . - * mmap.c: Likewise. - -2013-01-31 Ian Lance Taylor - - * dwarf.c (read_function_info): Permit fvec parameter to be NULL. - (dwarf_lookup_pc): Don't use ddata->fvec if threaded. - -2013-01-25 Jakub Jelinek - - PR other/56076 - * dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir - attribute was not seen. - -2013-01-16 Ian Lance Taylor - - * dwarf.c (struct unit): Add filename and abs_filename fields. - (build_address_map): Set new fields when reading unit. - (dwarf_lookup_pc): If we don't find an entry in the line table, - just return the main file name. - -2013-01-14 Richard Sandiford - - Update copyright years. - -2013-01-01 Ian Lance Taylor - - PR bootstrap/54834 - * Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I - $(MULTIBUILDTOP)/../../gcc/include. - * Makefile.in: Rebuild. - -2013-01-01 Ian Lance Taylor - - PR other/55536 - * mmap.c (backtrace_alloc): Don't call sync functions if not - threaded. - (backtrace_free): Likewise. - -2012-12-12 John David Anglin - - * mmapio.c: Define MAP_FAILED if not defined. - -2012-12-11 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@. - * configure.ac: If --with-target-subdir, add -frandom-seed=$@ - to EXTRA_FLAGS unconditionally, otherwise check whether the compiler - accepts it. - * Makefile.in: Regenerated. - * configure: Regenerated. - -2012-12-07 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Add -frandom-seed=$@. - * Makefile.in: Regenerated. - -2012-11-20 Ian Lance Taylor - - * dwarf.c (read_attribute): Always clear val. - -2012-11-13 Ian Lance Taylor - - PR other/55312 - * configure.ac: Only add -Werror if building a target library. - * configure: Rebuild. - -2012-11-12 Ian Lance Taylor - Rainer Orth - Gerald Pfeifer - - * configure.ac: Check for getexecname. - * fileline.c: #include . Define getexecname if not - available. - (fileline_initialize): Try to find the executable in a few - different ways. - * print.c (error_callback): Only print the filename if it came - from the backtrace state. - * configure, config.h.in: Rebuild. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Correct last patch: add - aligned, not size. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Make sure freed block is - aligned on 8-byte boundary. - -2012-10-26 Ian Lance Taylor - - PR other/55087 - * posix.c (backtrace_open): Add does_not_exist parameter. - * elf.c (phdr_callback): Do not warn if shared library could not - be opened. - * fileline.c (fileline_initialize): Update calls to - backtrace_open. - * internal.h (backtrace_open): Update declaration. - -2012-10-26 Jack Howarth - - PR target/55061 - * configure.ac: Check for _Unwind_GetIPInfo function declaration. - * configure: Regenerate. - -2012-10-24 Ian Lance Taylor - - PR target/55061 - * configure.ac: Check whether -funwind-tables option works. - * configure: Rebuild. - -2012-10-11 Ian Lance Taylor - - * configure.ac: Do not use dl_iterate_phdr on Solaris 10. - * configure: Rebuild. - -2012-10-10 Ian Lance Taylor - - * elf.c: Rename all Elf typedefs to start with b_elf, and be all - lower case. - -2012-10-10 Hans-Peter Nilsson - - * elf.c (elf_add_syminfo_data): Add casts to avoid warning. - -2012-10-09 Ian Lance Taylor - - * dwarf.c (dwarf_fileline): Add cast to avoid warning. - (backtrace_dwarf_add): Likewise. - -2012-10-09 Ian Lance Taylor - - Add support for tracing through shared libraries. - * configure.ac: Check for link.h and dl_iterate_phdr. - * elf.c: #include if system has dl_iterate_phdr. #undef - ELF macros before #defining them. - (dl_phdr_info, dl_iterate_phdr): Define if system does not have - dl_iterate_phdr. - (struct elf_syminfo_data): Add next field. - (elf_initialize_syminfo): Initialize next field. - (elf_add_syminfo_data): New static function. - (elf_add): New static function, broken out of - backtrace_initialize. Call backtrace_dwarf_add instead of - backtrace_dwarf_initialize. - (struct phdr_data): Define. - (phdr_callback): New static function. - (backtrace_initialize): Call elf_add. - * dwarf.c (struct dwarf_data): Add next and base_address fields. - (add_unit_addr): Add base_address parameter. Change all callers. - (add_unit_ranges, build_address_map): Likewise. - (add_line): Add ddata parameter. Change all callers. - (read_line_program, add_function_range): Likewise. - (dwarf_lookup_pc): New static function, broken out of - dwarf_fileline. - (dwarf_fileline): Call dwarf_lookup_pc. - (build_dwarf_data): New static function. - (backtrace_dwarf_add): New function. - (backtrace_dwarf_initialize): Remove. - * internal.h (backtrace_dwarf_initialize): Don't declare. - (backtrace_dwarf_add): Declare. - * configure, config.h.in: Rebuild. - -2012-10-04 Gerald Pfeifer - - * btest.c (f23): Avoid uninitialized variable warning. - -2012-10-04 Ian Lance Taylor - - * dwarf.c: If the system header files do not declare strnlen, - provide our own version. - -2012-10-03 Ian Lance Taylor - - * dwarf.c (read_uleb128): Fix overflow test. - (read_sleb128): Likewise. - (build_address_map): Don't change unit_buf.start. - -2012-10-02 Uros Bizjak - - PR other/54761 - * configure.ac (EXTRA_FLAGS): New. - * Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS). - * configure, Makefile.in: Regenerate. - -2012-09-29 Ian Lance Taylor - - PR other/54749 - * fileline.c (fileline_initialize): Pass errnum as -1 when - reporting that we could not read executable information after a - previous failure. - -2012-09-27 Ian Lance Taylor - - PR bootstrap/54732 - * configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE. - * Makefile.am: Add dependencies for all objects. - * configure, aclocal.m4, Makefile.in: Rebuild. - -2012-09-27 Ian Lance Taylor - - PR other/54726 - * elf.c (backtrace_initialize): Set *fileln_fn, not - state->fileln_fn. - -2012-09-19 Ian Lance Taylor - - * configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled - as a target library. - * configure: Rebuild. - -2012-09-19 Rainer Orth - Ian Lance Taylor - - * configure.ac (GCC_HEADER_STDINT): Invoke. - * backtrace.h: If we can't find , use "gstdint.h". - * btest.c: Don't include . - * dwarf.c: Likewise. - * configure, aclocal.m4, Makefile.in, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - PR bootstrap/54623 - * Makefile.am (AM_CPPFLAGS): Define. - (AM_CFLAGS): Remove -I options. - * Makefile.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * posix.c (O_BINARY): Define if not defined. - (backtrace_open): Pass O_BINARY to open. Only call fcntl if - HAVE_FCNTL is defined. - * configure.ac: Test for the fcntl function. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * btest.c (test1, test2, test3, test4): Add the unused attribute. - -2012-09-18 Ian Lance Taylor - - * dwarf.c: Correct test of HAVE_DECL_STRNLEN. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Add AC_USE_SYSTEM_EXTENSIONS. - * mmapio.c: Don't define _GNU_SOURCE. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Check whether strnlen is declared. - * dwarf.c: Declare strnlen if not declared. - * configure, config.h.in: Rebuild. - -2012-09-18 Rainer Orth - - * fileline.c: Include . - * mmap.c: Likewise. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54611 - * nounwind.c (backtrace_full): Rename from backtrace. Add state - parameter. - -2012-09-17 Gerald Pfeifer - - PR bootstrap/54611 - * nounwind.c (backtrace_simple): Add state parameter. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54609 - * unknown.c (unknown_fileline): Add state parameter, remove - fileline_data parameter, name error_callback parameter. - (backtrace_initialize): Add state parameter. - -2012-09-17 Ian Lance Taylor - - * Initial implementation. - -Copyright (C) 2012-2017 Free Software Foundation, Inc. - -Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. diff --git a/3rdparty/libbacktrace/README b/3rdparty/libbacktrace/README deleted file mode 100644 index e8b22574..00000000 --- a/3rdparty/libbacktrace/README +++ /dev/null @@ -1,23 +0,0 @@ -The libbacktrace library -Initially written by Ian Lance Taylor - -The libbacktrace library may be linked into a program or library and -used to produce symbolic backtraces. Sample uses would be to print a -detailed backtrace when an error occurs or to gather detailed -profiling information. - -The libbacktrace library is provided under a BSD license. See the -source files for the exact license text. - -The public functions are declared and documented in the header file -backtrace.h, which should be #include'd by a user of the library. - -Building libbacktrace will generate a file backtrace-supported.h, -which a user of the library may use to determine whether backtraces -will work. See the source file backtrace-supported.h.in for the -macros that it defines. - -As of September 2012, libbacktrace only supports ELF executables with -DWARF debugging information. The library is written to make it -straightforward to add support for other object file and debugging -formats. diff --git a/3rdparty/libbacktrace/alloc.c b/3rdparty/libbacktrace/alloc.c deleted file mode 100644 index e7e815b4..00000000 --- a/3rdparty/libbacktrace/alloc.c +++ /dev/null @@ -1,156 +0,0 @@ -/* alloc.c -- Memory allocation without mmap. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Allocation routines to use on systems that do not support anonymous - mmap. This implementation just uses malloc, which means that the - backtrace functions may not be safely invoked from a signal - handler. */ - -/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't - report an error. */ - -void * -backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, - size_t size, backtrace_error_callback error_callback, - void *data) -{ - void *ret; - - ret = malloc (size); - if (ret == NULL) - { - if (error_callback) - error_callback (data, "malloc", errno); - } - return ret; -} - -/* Free memory. */ - -void -backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED, - void *p, size_t size ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - free (p); -} - -/* Grow VEC by SIZE bytes. */ - -void * -backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED, - size_t size, backtrace_error_callback error_callback, - void *data, struct backtrace_vector *vec) -{ - void *ret; - - if (size > vec->alc) - { - size_t alc; - void *base; - - if (vec->size == 0) - alc = 32 * size; - else if (vec->size >= 4096) - alc = vec->size + 4096; - else - alc = 2 * vec->size; - - if (alc < vec->size + size) - alc = vec->size + size; - - base = realloc (vec->base, alc); - if (base == NULL) - { - error_callback (data, "realloc", errno); - return NULL; - } - - vec->base = base; - vec->alc = alc - vec->size; - } - - ret = (char *) vec->base + vec->size; - vec->size += size; - vec->alc -= size; - return ret; -} - -/* Finish the current allocation on VEC. */ - -void * -backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - void *ret; - - /* With this allocator we call realloc in backtrace_vector_grow, - which means we can't easily reuse the memory here. So just - release it. */ - if (!backtrace_vector_release (state, vec, error_callback, data)) - return NULL; - ret = vec->base; - vec->base = NULL; - vec->size = 0; - vec->alc = 0; - return ret; -} - -/* Release any extra space allocated for VEC. */ - -int -backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - vec->base = realloc (vec->base, vec->size); - if (vec->base == NULL) - { - error_callback (data, "realloc", errno); - return 0; - } - vec->alc = 0; - return 1; -} diff --git a/3rdparty/libbacktrace/atomic.c b/3rdparty/libbacktrace/atomic.c deleted file mode 100644 index b0d6a424..00000000 --- a/3rdparty/libbacktrace/atomic.c +++ /dev/null @@ -1,113 +0,0 @@ -/* atomic.c -- Support for atomic functions if not present. - Copyright (C) 2013-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* This file holds implementations of the atomic functions that are - used if the host compiler has the sync functions but not the atomic - functions, as is true of versions of GCC before 4.7. */ - -#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) - -/* Do an atomic load of a pointer. */ - -void * -backtrace_atomic_load_pointer (void *arg) -{ - void **pp; - void *p; - - pp = (void **) arg; - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; - return p; -} - -/* Do an atomic load of an int. */ - -int -backtrace_atomic_load_int (int *p) -{ - int i; - - i = *p; - while (!__sync_bool_compare_and_swap (p, i, i)) - i = *p; - return i; -} - -/* Do an atomic store of a pointer. */ - -void -backtrace_atomic_store_pointer (void *arg, void *p) -{ - void **pp; - void *old; - - pp = (void **) arg; - old = *pp; - while (!__sync_bool_compare_and_swap (pp, old, p)) - old = *pp; -} - -/* Do an atomic store of a size_t value. */ - -void -backtrace_atomic_store_size_t (size_t *p, size_t v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -/* Do an atomic store of a int value. */ - -void -backtrace_atomic_store_int (int *p, int v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -#endif diff --git a/3rdparty/libbacktrace/auxincl/dwarf2.h b/3rdparty/libbacktrace/auxincl/dwarf2.h deleted file mode 100644 index d135d8ac..00000000 --- a/3rdparty/libbacktrace/auxincl/dwarf2.h +++ /dev/null @@ -1,52 +0,0 @@ -/* dwarf2.h -- minimal GCC dwarf2.h replacement for libbacktrace - Contributed by Alexander Monakov, ISP RAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_AUX_DWARF2_H -#define BACKTRACE_AUX_DWARF2_H - -/* Use the system header for the bulk of the definitions. */ -#include - -/* Provide stub enum tags. */ -enum dwarf_attribute {_dummy_dwarf_attribute}; -enum dwarf_form {_dummy_dwarf_form}; -enum dwarf_tag {_dummy_dwarf_tag}; - -/* Define potentially missing enum values. */ -#define DW_FORM_GNU_addr_index 0x1f01 -#define DW_FORM_GNU_str_index 0x1f02 - -#define DW_FORM_GNU_ref_alt 0x1f20 -#define DW_FORM_GNU_strp_alt 0x1f21 - -#define DW_LNS_extended_op 0 - -#endif diff --git a/3rdparty/libbacktrace/auxincl/filenames.h b/3rdparty/libbacktrace/auxincl/filenames.h deleted file mode 100644 index 000dd30e..00000000 --- a/3rdparty/libbacktrace/auxincl/filenames.h +++ /dev/null @@ -1,40 +0,0 @@ -/* filenames.h -- minimal GCC filenames.h replacement for libbacktrace - Contributed by Alexander Monakov, ISP RAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_AUX_FILENAMES_H -#define BACKTRACE_AUX_FILENAMES_H - -/* Assume POSIX paths. */ - -#define IS_DIR_SEPARATOR(c) ((c) == '/') -#define IS_ABSOLUTE_PATH(f) ((f)[0] == '/') - -#endif diff --git a/3rdparty/libbacktrace/backtrace-supported.h.in b/3rdparty/libbacktrace/backtrace-supported.h.in deleted file mode 100644 index 342e8c42..00000000 --- a/3rdparty/libbacktrace/backtrace-supported.h.in +++ /dev/null @@ -1,66 +0,0 @@ -/* backtrace-supported.h.in -- Whether stack backtrace is supported. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -/* The file backtrace-supported.h.in is used by configure to generate - the file backtrace-supported.h. The file backtrace-supported.h may - be #include'd to see whether the backtrace library will be able to - get a backtrace and produce symbolic information. */ - - -/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library - should work, 0 if it will not. Libraries may #include this to make - other arrangements. */ - -#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@ - -/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace - library will call malloc as it works, 0 if it will call mmap - instead. This may be used to determine whether it is safe to call - the backtrace functions from a signal handler. In general this - only applies to calls like backtrace and backtrace_pcinfo. It does - not apply to backtrace_simple, which never calls malloc. It does - not apply to backtrace_print, which always calls fprintf and - therefore malloc. */ - -#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@ - -/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace - library is configured with threading support, 0 if not. If this is - 0, the threaded parameter to backtrace_create_state must be passed - as 0. */ - -#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@ - -/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo - will work for variables. It will always work for functions. */ - -#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@ diff --git a/3rdparty/libbacktrace/backtrace.c b/3rdparty/libbacktrace/backtrace.c deleted file mode 100644 index 67a10e25..00000000 --- a/3rdparty/libbacktrace/backtrace.c +++ /dev/null @@ -1,129 +0,0 @@ -/* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "unwind.h" -#include "backtrace.h" -#include "internal.h" - -/* The main backtrace_full routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_full_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routines. */ - void *data; - /* Value to return from backtrace_full. */ - int ret; - /* Whether there is any memory available. */ - int can_alloc; -}; - -/* Unwind library callback routine. This is passed to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_data *bdata = (struct backtrace_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - if (!bdata->can_alloc) - bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); - else - bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, - bdata->error_callback, bdata->data); - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a stack backtrace. */ - -int -backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_data bdata; - void *p; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - - /* If we can't allocate any memory at all, don't try to produce - file/line information. */ - p = backtrace_alloc (state, 4096, NULL, NULL); - if (p == NULL) - bdata.can_alloc = 0; - else - { - backtrace_free (state, p, 4096, NULL, NULL); - bdata.can_alloc = 1; - } - - _Unwind_Backtrace (unwind, &bdata); - return bdata.ret; -} diff --git a/3rdparty/libbacktrace/backtrace.h b/3rdparty/libbacktrace/backtrace.h deleted file mode 100644 index 14863cf2..00000000 --- a/3rdparty/libbacktrace/backtrace.h +++ /dev/null @@ -1,199 +0,0 @@ -/* backtrace.h -- Public header file for stack backtrace library. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_H -#define BACKTRACE_H - -#include -#include - -/* We want to get a definition for uintptr_t, but we still care about - systems that don't have . */ -#if defined(__GLIBC__) && __GLIBC__ >= 2 - -#include - -#elif defined(HAVE_STDINT_H) - -#include - -#else - -/* Systems that don't have must provide gstdint.h, e.g., - from GCC_HEADER_STDINT in configure.ac. */ -#include "gstdint.h" - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* The backtrace state. This struct is intentionally not defined in - the public interface. */ - -struct backtrace_state; - -/* The type of the error callback argument to backtrace functions. - This function, if not NULL, will be called for certain error cases. - The DATA argument is passed to the function that calls this one. - The MSG argument is an error message. The ERRNUM argument, if - greater than 0, holds an errno value. The MSG buffer may become - invalid after this function returns. - - As a special case, the ERRNUM argument will be passed as -1 if no - debug info can be found for the executable, but the function - requires debug info (e.g., backtrace_full, backtrace_pcinfo). The - MSG in this case will be something along the lines of "no debug - info". Similarly, ERRNUM will be passed as -1 if there is no - symbol table, but the function requires a symbol table (e.g., - backtrace_syminfo). This may be used as a signal that some other - approach should be tried. */ - -typedef void (*backtrace_error_callback) (void *data, const char *msg, - int errnum); - -/* Create state information for the backtrace routines. This must be - called before any of the other routines, and its return value must - be passed to all of the other routines. FILENAME is the path name - of the executable file; if it is NULL the library will try - system-specific path names. If not NULL, FILENAME must point to a - permanent buffer. If THREADED is non-zero the state may be - accessed by multiple threads simultaneously, and the library will - use appropriate atomic operations. If THREADED is zero the state - may only be accessed by one thread at a time. This returns a state - pointer on success, NULL on error. If an error occurs, this will - call the ERROR_CALLBACK routine. */ - -extern struct backtrace_state *backtrace_create_state ( - const char *filename, int threaded, - backtrace_error_callback error_callback, void *data); - -/* The type of the callback argument to the backtrace_full function. - DATA is the argument passed to backtrace_full. PC is the program - counter. FILENAME is the name of the file containing PC, or NULL - if not available. LINENO is the line number in FILENAME containing - PC, or 0 if not available. FUNCTION is the name of the function - containing PC, or NULL if not available. This should return 0 to - continuing tracing. The FILENAME and FUNCTION buffers may become - invalid after this function returns. */ - -typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, - const char *filename, int lineno, - const char *function); - -/* Get a full stack backtrace. SKIP is the number of frames to skip; - passing 0 will start the trace with the function calling - backtrace_full. DATA is passed to the callback routine. If any - call to CALLBACK returns a non-zero value, the stack backtrace - stops, and backtrace returns that value; this may be used to limit - the number of stack frames desired. If all calls to CALLBACK - return 0, backtrace returns 0. The backtrace_full function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function requires debug info for the executable. */ - -extern int backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to the backtrace_simple function. - DATA is the argument passed to simple_backtrace. PC is the program - counter. This should return 0 to continue tracing. */ - -typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc); - -/* Get a simple backtrace. SKIP is the number of frames to skip, as - in backtrace. DATA is passed to the callback routine. If any call - to CALLBACK returns a non-zero value, the stack backtrace stops, - and backtrace_simple returns that value. Otherwise - backtrace_simple returns 0. The backtrace_simple function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function does not require any debug info for the executable. */ - -extern int backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* Print the current backtrace in a user readable format to a FILE. - SKIP is the number of frames to skip, as in backtrace_full. Any - error messages are printed to stderr. This function requires debug - info for the executable. */ - -extern void backtrace_print (struct backtrace_state *state, int skip, FILE *); - -/* Given PC, a program counter in the current program, call the - callback function with filename, line number, and function name - information. This will normally call the callback function exactly - once. However, if the PC happens to describe an inlined call, and - the debugging information contains the necessary information, then - this may call the callback function multiple times. This will make - at least one call to either CALLBACK or ERROR_CALLBACK. This - returns the first non-zero value returned by CALLBACK, or 0. */ - -extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to backtrace_syminfo. DATA and - PC are the arguments passed to backtrace_syminfo. SYMNAME is the - name of the symbol for the corresponding code. SYMVAL is the - value and SYMSIZE is the size of the symbol. SYMNAME will be NULL - if no error occurred but the symbol could not be found. */ - -typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, - const char *symname, - uintptr_t symval, - uintptr_t symsize); - -/* Given ADDR, an address or program counter in the current program, - call the callback information with the symbol name and value - describing the function or variable in which ADDR may be found. - This will call either CALLBACK or ERROR_CALLBACK exactly once. - This returns 1 on success, 0 on failure. This function requires - the symbol table but does not require the debug info. Note that if - the symbol table is present but ADDR could not be found in the - table, CALLBACK will be called with a NULL SYMNAME argument. - Returns 1 on success, 0 on error. */ - -extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, - void *data); - -#ifdef __cplusplus -} /* End extern "C". */ -#endif - -#endif diff --git a/3rdparty/libbacktrace/config.h.in.cmake b/3rdparty/libbacktrace/config.h.in.cmake deleted file mode 100644 index 41dbc623..00000000 --- a/3rdparty/libbacktrace/config.h.in.cmake +++ /dev/null @@ -1,28 +0,0 @@ -/* ELF size: 32 or 64 */ -#define BACKTRACE_ELF_SIZE @BACKTRACE_ELF_SIZE@ - -/* Define to 1 if you have the declaration of `strnlen', and to 0 if you - don't. */ -#cmakedefine HAVE_DECL_STRNLEN 1 - -/* Define if dl_iterate_phdr is available. */ -#cmakedefine HAVE_DL_ITERATE_PHDR 1 - -/* Define to 1 if you have the fcntl function */ -#cmakedefine HAVE_FCNTL 1 - -/* Define if getexecname is available. */ -#cmakedefine HAVE_GETEXECNAME 1 - -/* Define if _Unwind_GetIPInfo is available. */ -#cmakedefine HAVE_GETIPINFO 1 - -/* Define to 1 if you have the __sync functions */ -#cmakedefine HAVE_SYNC_FUNCTIONS 1 - -/* Define to 1 if you have the __atomic functions */ -#cmakedefine HAVE_ATOMIC_FUNCTION 1 - -#cmakedefine HAVE_READLINK 1 - -#cmakedefine HAVE_LSTAT 1 diff --git a/3rdparty/libbacktrace/dwarf.c b/3rdparty/libbacktrace/dwarf.c deleted file mode 100644 index 8dd80ca4..00000000 --- a/3rdparty/libbacktrace/dwarf.c +++ /dev/null @@ -1,3043 +0,0 @@ -/* dwarf.c -- Get file/line information from DWARF for backtraces. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "dwarf2.h" -#include "filenames.h" - -#include "backtrace.h" -#include "internal.h" - -#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN - -/* If strnlen is not declared, provide our own version. */ - -static size_t -xstrnlen (const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; ++i) - if (s[i] == '\0') - break; - return i; -} - -#define strnlen xstrnlen - -#endif - -/* A buffer to read DWARF info. */ - -struct dwarf_buf -{ - /* Buffer name for error messages. */ - const char *name; - /* Start of the buffer. */ - const unsigned char *start; - /* Next byte to read. */ - const unsigned char *buf; - /* The number of bytes remaining. */ - size_t left; - /* Whether the data is big-endian. */ - int is_bigendian; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data for error_callback. */ - void *data; - /* Non-zero if we've reported an underflow error. */ - int reported_underflow; -}; - -/* A single attribute in a DWARF abbreviation. */ - -struct attr -{ - /* The attribute name. */ - enum dwarf_attribute name; - /* The attribute form. */ - enum dwarf_form form; -}; - -/* A single DWARF abbreviation. */ - -struct abbrev -{ - /* The abbrev code--the number used to refer to the abbrev. */ - uint64_t code; - /* The entry tag. */ - enum dwarf_tag tag; - /* Non-zero if this abbrev has child entries. */ - int has_children; - /* The number of attributes. */ - size_t num_attrs; - /* The attributes. */ - struct attr *attrs; -}; - -/* The DWARF abbreviations for a compilation unit. This structure - only exists while reading the compilation unit. Most DWARF readers - seem to a hash table to map abbrev ID's to abbrev entries. - However, we primarily care about GCC, and GCC simply issues ID's in - numerical order starting at 1. So we simply keep a sorted vector, - and try to just look up the code. */ - -struct abbrevs -{ - /* The number of abbrevs in the vector. */ - size_t num_abbrevs; - /* The abbrevs, sorted by the code field. */ - struct abbrev *abbrevs; -}; - -/* The different kinds of attribute values. */ - -enum attr_val_encoding -{ - /* An address. */ - ATTR_VAL_ADDRESS, - /* A unsigned integer. */ - ATTR_VAL_UINT, - /* A sigd integer. */ - ATTR_VAL_SINT, - /* A string. */ - ATTR_VAL_STRING, - /* An offset to other data in the containing unit. */ - ATTR_VAL_REF_UNIT, - /* An offset to other data within the .dwarf_info section. */ - ATTR_VAL_REF_INFO, - /* An offset to data in some other section. */ - ATTR_VAL_REF_SECTION, - /* A type signature. */ - ATTR_VAL_REF_TYPE, - /* A block of data (not represented). */ - ATTR_VAL_BLOCK, - /* An expression (not represented). */ - ATTR_VAL_EXPR, -}; - -/* An attribute value. */ - -struct attr_val -{ - /* How the value is stored in the field u. */ - enum attr_val_encoding encoding; - union - { - /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */ - uint64_t uint; - /* ATTR_VAL_SINT. */ - int64_t sint; - /* ATTR_VAL_STRING. */ - const char *string; - /* ATTR_VAL_BLOCK not stored. */ - } u; -}; - -/* The line number program header. */ - -struct line_header -{ - /* The version of the line number information. */ - int version; - /* The minimum instruction length. */ - unsigned int min_insn_len; - /* The maximum number of ops per instruction. */ - unsigned int max_ops_per_insn; - /* The line base for special opcodes. */ - int line_base; - /* The line range for special opcodes. */ - unsigned int line_range; - /* The opcode base--the first special opcode. */ - unsigned int opcode_base; - /* Opcode lengths, indexed by opcode - 1. */ - const unsigned char *opcode_lengths; - /* The number of directory entries. */ - size_t dirs_count; - /* The directory entries. */ - const char **dirs; - /* The number of filenames. */ - size_t filenames_count; - /* The filenames. */ - const char **filenames; -}; - -/* Map a single PC value to a file/line. We will keep a vector of - these sorted by PC value. Each file/line will be correct from the - PC up to the PC of the next entry if there is one. We allocate one - extra entry at the end so that we can use bsearch. */ - -struct line -{ - /* PC. */ - uintptr_t pc; - /* File name. Many entries in the array are expected to point to - the same file name. */ - const char *filename; - /* Line number. */ - int lineno; - /* Index of the object in the original array read from the DWARF - section, before it has been sorted. The index makes it possible - to use Quicksort and maintain stability. */ - int idx; -}; - -/* A growable vector of line number information. This is used while - reading the line numbers. */ - -struct line_vector -{ - /* Memory. This is an array of struct line. */ - struct backtrace_vector vec; - /* Number of valid mappings. */ - size_t count; -}; - -/* A function described in the debug info. */ - -struct function -{ - /* The name of the function. */ - const char *name; - /* If this is an inlined function, the filename of the call - site. */ - const char *caller_filename; - /* If this is an inlined function, the line number of the call - site. */ - int caller_lineno; - /* Map PC ranges to inlined functions. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a function. This maps a PC value to a - specific function. */ - -struct function_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Function for this address range. */ - struct function *function; -}; - -/* A growable vector of function address ranges. */ - -struct function_vector -{ - /* Memory. This is an array of struct function_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* A DWARF compilation unit. This only holds the information we need - to map a PC to a file and line. */ - -struct unit -{ - /* The first entry for this compilation unit. */ - const unsigned char *unit_data; - /* The length of the data for this compilation unit. */ - size_t unit_data_len; - /* The offset of UNIT_DATA from the start of the information for - this compilation unit. */ - size_t unit_data_offset; - /* DWARF version. */ - int version; - /* Whether unit is DWARF64. */ - int is_dwarf64; - /* Address size. */ - int addrsize; - /* Offset into line number information. */ - off_t lineoff; - /* Primary source file. */ - const char *filename; - /* Compilation command working directory. */ - const char *comp_dir; - /* Absolute file name, only set if needed. */ - const char *abs_filename; - /* The abbreviations for this unit. */ - struct abbrevs abbrevs; - - /* The fields above this point are read in during initialization and - may be accessed freely. The fields below this point are read in - as needed, and therefore require care, as different threads may - try to initialize them simultaneously. */ - - /* PC to line number mapping. This is NULL if the values have not - been read. This is (struct line *) -1 if there was an error - reading the values. */ - struct line *lines; - /* Number of entries in lines. */ - size_t lines_count; - /* PC ranges to function. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a compilation unit. This maps a PC value to a - specific compilation unit. Note that we invert the representation - in DWARF: instead of listing the units and attaching a list of - ranges, we list the ranges and have each one point to the unit. - This lets us do a binary search to find the unit. */ - -struct unit_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Compilation unit for this address range. */ - struct unit *u; -}; - -/* A growable vector of compilation unit address ranges. */ - -struct unit_addrs_vector -{ - /* Memory. This is an array of struct unit_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* The information we need to map a PC to a file and line. */ - -struct dwarf_data -{ - /* The data for the next file we know about. */ - struct dwarf_data *next; - /* The base address for this file. */ - uintptr_t base_address; - /* A sorted list of address ranges. */ - struct unit_addrs *addrs; - /* Number of address ranges in list. */ - size_t addrs_count; - /* The unparsed .debug_info section. */ - const unsigned char *dwarf_info; - size_t dwarf_info_size; - /* The unparsed .debug_line section. */ - const unsigned char *dwarf_line; - size_t dwarf_line_size; - /* The unparsed .debug_ranges section. */ - const unsigned char *dwarf_ranges; - size_t dwarf_ranges_size; - /* The unparsed .debug_str section. */ - const unsigned char *dwarf_str; - size_t dwarf_str_size; - /* Whether the data is big-endian or not. */ - int is_bigendian; - /* A vector used for function addresses. We keep this here so that - we can grow the vector as we read more functions. */ - struct function_vector fvec; -}; - -/* Report an error for a DWARF buffer. */ - -static void -dwarf_buf_error (struct dwarf_buf *buf, const char *msg) -{ - char b[200]; - - snprintf (b, sizeof b, "%s in %s at %d", - msg, buf->name, (int) (buf->buf - buf->start)); - buf->error_callback (buf->data, b, 0); -} - -/* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -require (struct dwarf_buf *buf, size_t count) -{ - if (buf->left >= count) - return 1; - - if (!buf->reported_underflow) - { - dwarf_buf_error (buf, "DWARF underflow"); - buf->reported_underflow = 1; - } - - return 0; -} - -/* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -advance (struct dwarf_buf *buf, size_t count) -{ - if (!require (buf, count)) - return 0; - buf->buf += count; - buf->left -= count; - return 1; -} - -/* Read one byte from BUF and advance 1 byte. */ - -static unsigned char -read_byte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return p[0]; -} - -/* Read a signed char from BUF and advance 1 byte. */ - -static signed char -read_sbyte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return (*p ^ 0x80) - 0x80; -} - -/* Read a uint16 from BUF and advance 2 bytes. */ - -static uint16_t -read_uint16 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 2)) - return 0; - if (buf->is_bigendian) - return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; - else - return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; -} - -/* Read a uint32 from BUF and advance 4 bytes. */ - -static uint32_t -read_uint32 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 4)) - return 0; - if (buf->is_bigendian) - return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) - | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); - else - return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) - | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); -} - -/* Read a uint64 from BUF and advance 8 bytes. */ - -static uint64_t -read_uint64 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 8)) - return 0; - if (buf->is_bigendian) - return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48) - | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32) - | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16) - | ((uint64_t) p[6] << 8) | (uint64_t) p[7]); - else - return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) - | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) - | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) - | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); -} - -/* Read an offset from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_offset (struct dwarf_buf *buf, int is_dwarf64) -{ - if (is_dwarf64) - return read_uint64 (buf); - else - return read_uint32 (buf); -} - -/* Read an address from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_address (struct dwarf_buf *buf, int addrsize) -{ - switch (addrsize) - { - case 1: - return read_byte (buf); - case 2: - return read_uint16 (buf); - case 4: - return read_uint32 (buf); - case 8: - return read_uint64 (buf); - default: - dwarf_buf_error (buf, "unrecognized address size"); - return 0; - } -} - -/* Return whether a value is the highest possible address, given the - address size. */ - -static int -is_highest_address (uint64_t address, int addrsize) -{ - switch (addrsize) - { - case 1: - return address == (unsigned char) -1; - case 2: - return address == (uint16_t) -1; - case 4: - return address == (uint32_t) -1; - case 8: - return address == (uint64_t) -1; - default: - return 0; - } -} - -/* Read an unsigned LEB128 number. */ - -static uint64_t -read_uleb128 (struct dwarf_buf *buf) -{ - uint64_t ret; - unsigned int shift; - int overflow; - unsigned char b; - - ret = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - ret |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - return ret; -} - -/* Read a signed LEB128 number. */ - -static int64_t -read_sleb128 (struct dwarf_buf *buf) -{ - uint64_t val; - unsigned int shift; - int overflow; - unsigned char b; - - val = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - val |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - if ((b & 0x40) != 0 && shift < 64) - val |= ((uint64_t) -1) << shift; - - return (int64_t) val; -} - -/* Return the length of an LEB128 number. */ - -static size_t -leb128_len (const unsigned char *p) -{ - size_t ret; - - ret = 1; - while ((*p & 0x80) != 0) - { - ++p; - ++ret; - } - return ret; -} - -/* Free an abbreviations structure. */ - -static void -free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, - backtrace_error_callback error_callback, void *data) -{ - size_t i; - - for (i = 0; i < abbrevs->num_abbrevs; ++i) - backtrace_free (state, abbrevs->abbrevs[i].attrs, - abbrevs->abbrevs[i].num_attrs * sizeof (struct attr), - error_callback, data); - backtrace_free (state, abbrevs->abbrevs, - abbrevs->num_abbrevs * sizeof (struct abbrev), - error_callback, data); - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; -} - -/* Read an attribute value. Returns 1 on success, 0 on failure. If - the value can be represented as a uint64_t, sets *VAL and sets - *IS_VALID to 1. We don't try to store the value of other attribute - forms, because we don't care about them. */ - -static int -read_attribute (enum dwarf_form form, struct dwarf_buf *buf, - int is_dwarf64, int version, int addrsize, - const unsigned char *dwarf_str, size_t dwarf_str_size, - struct attr_val *val) -{ - /* Avoid warnings about val.u.FIELD may be used uninitialized if - this function is inlined. The warnings aren't valid but can - occur because the different fields are set and used - conditionally. */ - memset (val, 0, sizeof *val); - - switch (form) - { - case DW_FORM_addr: - val->encoding = ATTR_VAL_ADDRESS; - val->u.uint = read_address (buf, addrsize); - return 1; - case DW_FORM_block2: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint16 (buf)); - case DW_FORM_block4: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint32 (buf)); - case DW_FORM_data2: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_data4: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_data8: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_string: - val->encoding = ATTR_VAL_STRING; - val->u.string = (const char *) buf->buf; - return advance (buf, strnlen ((const char *) buf->buf, buf->left) + 1); - case DW_FORM_block: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_block1: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_byte (buf)); - case DW_FORM_data1: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_flag: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_sdata: - val->encoding = ATTR_VAL_SINT; - val->u.sint = read_sleb128 (buf); - return 1; - case DW_FORM_strp: - { - uint64_t offset; - - offset = read_offset (buf, is_dwarf64); - if (offset >= dwarf_str_size) - { - dwarf_buf_error (buf, "DW_FORM_strp out of range"); - return 0; - } - val->encoding = ATTR_VAL_STRING; - val->u.string = (const char *) dwarf_str + offset; - return 1; - } - case DW_FORM_udata: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_ref_addr: - val->encoding = ATTR_VAL_REF_INFO; - if (version == 2) - val->u.uint = read_address (buf, addrsize); - else - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_ref1: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_ref2: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_ref4: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_ref8: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_ref_udata: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_indirect: - { - uint64_t form; - - form = read_uleb128 (buf); - return read_attribute ((enum dwarf_form) form, buf, is_dwarf64, - version, addrsize, dwarf_str, dwarf_str_size, - val); - } - case DW_FORM_sec_offset: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_exprloc: - val->encoding = ATTR_VAL_EXPR; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_flag_present: - val->encoding = ATTR_VAL_UINT; - val->u.uint = 1; - return 1; - case DW_FORM_ref_sig8: - val->encoding = ATTR_VAL_REF_TYPE; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_GNU_addr_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_str_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_ref_alt: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_GNU_strp_alt: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - default: - dwarf_buf_error (buf, "unrecognized DWARF form"); - return 0; - } -} - -/* Compare function_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -function_addrs_compare (const void *v1, const void *v2) -{ - const struct function_addrs *a1 = (const struct function_addrs *) v1; - const struct function_addrs *a2 = (const struct function_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - return strcmp (a1->function->name, a2->function->name); -} - -/* Compare a PC against a function_addrs for bsearch. Note that if - there are multiple ranges containing PC, which one will be returned - is unpredictable. We compensate for that in dwarf_fileline. */ - -static int -function_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct function_addrs *entry = (const struct function_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Add a new compilation unit address range to a vector. Returns 1 on - success, 0 on failure. */ - -static int -add_unit_addr (struct backtrace_state *state, uintptr_t base_address, - struct unit_addrs addrs, - backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *vec) -{ - struct unit_addrs *p; - - /* Add in the base address of the module here, so that we can look - up the PC directly. */ - addrs.low += base_address; - addrs.high += base_address; - - /* Try to merge with the last entry. */ - if (vec->count > 0) - { - p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); - if ((addrs.low == p->high || addrs.low == p->high + 1) - && addrs.u == p->u) - { - if (addrs.high > p->high) - p->high = addrs.high; - return 1; - } - } - - p = ((struct unit_addrs *) - backtrace_vector_grow (state, sizeof (struct unit_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - *p = addrs; - ++vec->count; - return 1; -} - -/* Free a unit address vector. */ - -static void -free_unit_addrs_vector (struct backtrace_state *state, - struct unit_addrs_vector *vec, - backtrace_error_callback error_callback, void *data) -{ - struct unit_addrs *addrs; - size_t i; - - addrs = (struct unit_addrs *) vec->vec.base; - for (i = 0; i < vec->count; ++i) - free_abbrevs (state, &addrs[i].u->abbrevs, error_callback, data); -} - -/* Compare unit_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -unit_addrs_compare (const void *v1, const void *v2) -{ - const struct unit_addrs *a1 = (const struct unit_addrs *) v1; - const struct unit_addrs *a2 = (const struct unit_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - if (a1->u->lineoff < a2->u->lineoff) - return -1; - if (a1->u->lineoff > a2->u->lineoff) - return 1; - return 0; -} - -/* Compare a PC against a unit_addrs for bsearch. Note that if there - are multiple ranges containing PC, which one will be returned is - unpredictable. We compensate for that in dwarf_fileline. */ - -static int -unit_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct unit_addrs *entry = (const struct unit_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Sort the line vector by PC. We want a stable sort here to maintain - the order of lines for the same PC values. Since the sequence is - being sorted in place, their addresses cannot be relied on to - maintain stability. That is the purpose of the index member. */ - -static int -line_compare (const void *v1, const void *v2) -{ - const struct line *ln1 = (const struct line *) v1; - const struct line *ln2 = (const struct line *) v2; - - if (ln1->pc < ln2->pc) - return -1; - else if (ln1->pc > ln2->pc) - return 1; - else if (ln1->idx < ln2->idx) - return -1; - else if (ln1->idx > ln2->idx) - return 1; - else - return 0; -} - -/* Find a PC in a line vector. We always allocate an extra entry at - the end of the lines vector, so that this routine can safely look - at the next entry. Note that when there are multiple mappings for - the same PC value, this will return the last one. */ - -static int -line_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct line *entry = (const struct line *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->pc) - return -1; - else if (pc >= (entry + 1)->pc) - return 1; - else - return 0; -} - -/* Sort the abbrevs by the abbrev code. This function is passed to - both qsort and bsearch. */ - -static int -abbrev_compare (const void *v1, const void *v2) -{ - const struct abbrev *a1 = (const struct abbrev *) v1; - const struct abbrev *a2 = (const struct abbrev *) v2; - - if (a1->code < a2->code) - return -1; - else if (a1->code > a2->code) - return 1; - else - { - /* This really shouldn't happen. It means there are two - different abbrevs with the same code, and that means we don't - know which one lookup_abbrev should return. */ - return 0; - } -} - -/* Read the abbreviation table for a compilation unit. Returns 1 on - success, 0 on failure. */ - -static int -read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct abbrevs *abbrevs) -{ - struct dwarf_buf abbrev_buf; - struct dwarf_buf count_buf; - size_t num_abbrevs; - - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; - - if (abbrev_offset >= dwarf_abbrev_size) - { - error_callback (data, "abbrev offset out of range", 0); - return 0; - } - - abbrev_buf.name = ".debug_abbrev"; - abbrev_buf.start = dwarf_abbrev; - abbrev_buf.buf = dwarf_abbrev + abbrev_offset; - abbrev_buf.left = dwarf_abbrev_size - abbrev_offset; - abbrev_buf.is_bigendian = is_bigendian; - abbrev_buf.error_callback = error_callback; - abbrev_buf.data = data; - abbrev_buf.reported_underflow = 0; - - /* Count the number of abbrevs in this list. */ - - count_buf = abbrev_buf; - num_abbrevs = 0; - while (read_uleb128 (&count_buf) != 0) - { - if (count_buf.reported_underflow) - return 0; - ++num_abbrevs; - // Skip tag. - read_uleb128 (&count_buf); - // Skip has_children. - read_byte (&count_buf); - // Skip attributes. - while (read_uleb128 (&count_buf) != 0) - read_uleb128 (&count_buf); - // Skip form of last attribute. - read_uleb128 (&count_buf); - } - - if (count_buf.reported_underflow) - return 0; - - if (num_abbrevs == 0) - return 1; - - abbrevs->num_abbrevs = num_abbrevs; - abbrevs->abbrevs = ((struct abbrev *) - backtrace_alloc (state, - num_abbrevs * sizeof (struct abbrev), - error_callback, data)); - if (abbrevs->abbrevs == NULL) - return 0; - memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev)); - - num_abbrevs = 0; - while (1) - { - uint64_t code; - struct abbrev a; - size_t num_attrs; - struct attr *attrs; - - if (abbrev_buf.reported_underflow) - goto fail; - - code = read_uleb128 (&abbrev_buf); - if (code == 0) - break; - - a.code = code; - a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf); - a.has_children = read_byte (&abbrev_buf); - - count_buf = abbrev_buf; - num_attrs = 0; - while (read_uleb128 (&count_buf) != 0) - { - ++num_attrs; - read_uleb128 (&count_buf); - } - - if (num_attrs == 0) - { - attrs = NULL; - read_uleb128 (&abbrev_buf); - read_uleb128 (&abbrev_buf); - } - else - { - attrs = ((struct attr *) - backtrace_alloc (state, num_attrs * sizeof *attrs, - error_callback, data)); - if (attrs == NULL) - goto fail; - num_attrs = 0; - while (1) - { - uint64_t name; - uint64_t form; - - name = read_uleb128 (&abbrev_buf); - form = read_uleb128 (&abbrev_buf); - if (name == 0) - break; - attrs[num_attrs].name = (enum dwarf_attribute) name; - attrs[num_attrs].form = (enum dwarf_form) form; - ++num_attrs; - } - } - - a.num_attrs = num_attrs; - a.attrs = attrs; - - abbrevs->abbrevs[num_abbrevs] = a; - ++num_abbrevs; - } - - backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - - return 1; - - fail: - free_abbrevs (state, abbrevs, error_callback, data); - return 0; -} - -/* Return the abbrev information for an abbrev code. */ - -static const struct abbrev * -lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, - backtrace_error_callback error_callback, void *data) -{ - struct abbrev key; - void *p; - - /* With GCC, where abbrevs are simply numbered in order, we should - be able to just look up the entry. */ - if (code - 1 < abbrevs->num_abbrevs - && abbrevs->abbrevs[code - 1].code == code) - return &abbrevs->abbrevs[code - 1]; - - /* Otherwise we have to search. */ - memset (&key, 0, sizeof key); - key.code = code; - p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - if (p == NULL) - { - error_callback (data, "invalid abbreviation code", 0); - return NULL; - } - return (const struct abbrev *) p; -} - -/* Add non-contiguous address ranges for a compilation unit. Returns - 1 on success, 0 on failure. */ - -static int -add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, - struct unit *u, uint64_t ranges, uint64_t base, - int is_bigendian, const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *addrs) -{ - struct dwarf_buf ranges_buf; - - if (ranges >= dwarf_ranges_size) - { - error_callback (data, "ranges offset out of range", 0); - return 0; - } - - ranges_buf.name = ".debug_ranges"; - ranges_buf.start = dwarf_ranges; - ranges_buf.buf = dwarf_ranges + ranges; - ranges_buf.left = dwarf_ranges_size - ranges; - ranges_buf.is_bigendian = is_bigendian; - ranges_buf.error_callback = error_callback; - ranges_buf.data = data; - ranges_buf.reported_underflow = 0; - - while (1) - { - uint64_t low; - uint64_t high; - - if (ranges_buf.reported_underflow) - return 0; - - low = read_address (&ranges_buf, u->addrsize); - high = read_address (&ranges_buf, u->addrsize); - - if (low == 0 && high == 0) - break; - - if (is_highest_address (low, u->addrsize)) - base = high; - else - { - struct unit_addrs a; - - a.low = low + base; - a.high = high + base; - a.u = u; - if (!add_unit_addr (state, base_address, a, error_callback, data, - addrs)) - return 0; - } - } - - if (ranges_buf.reported_underflow) - return 0; - - return 1; -} - -/* Find the address range covered by a compilation unit, reading from - UNIT_BUF and adding values to U. Returns 1 if all data could be - read, 0 if there is some error. */ - -static int -find_address_ranges (struct backtrace_state *state, uintptr_t base_address, - struct dwarf_buf *unit_buf, - const unsigned char *dwarf_str, size_t dwarf_str_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct unit *u, - struct unit_addrs_vector *addrs) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - uint64_t lowpc; - int have_lowpc; - uint64_t highpc; - int have_highpc; - int highpc_is_relative; - uint64_t ranges; - int have_ranges; - size_t i; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - lowpc = 0; - have_lowpc = 0; - highpc = 0; - have_highpc = 0; - highpc_is_relative = 0; - ranges = 0; - have_ranges = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, unit_buf, - u->is_dwarf64, u->version, u->addrsize, - dwarf_str, dwarf_str_size, &val)) - return 0; - - switch (abbrev->attrs[i].name) - { - case DW_AT_low_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - lowpc = val.u.uint; - have_lowpc = 1; - } - break; - - case DW_AT_high_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - highpc = val.u.uint; - have_highpc = 1; - } - else if (val.encoding == ATTR_VAL_UINT) - { - highpc = val.u.uint; - have_highpc = 1; - highpc_is_relative = 1; - } - break; - - case DW_AT_ranges: - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION) - { - ranges = val.u.uint; - have_ranges = 1; - } - break; - - case DW_AT_stmt_list: - if (abbrev->tag == DW_TAG_compile_unit - && (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION)) - u->lineoff = val.u.uint; - break; - - case DW_AT_name: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_STRING) - u->filename = val.u.string; - break; - - case DW_AT_comp_dir: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_STRING) - u->comp_dir = val.u.string; - break; - - default: - break; - } - } - - if (abbrev->tag == DW_TAG_compile_unit - || abbrev->tag == DW_TAG_subprogram) - { - if (have_ranges) - { - if (!add_unit_ranges (state, base_address, u, ranges, lowpc, - is_bigendian, dwarf_ranges, - dwarf_ranges_size, error_callback, - data, addrs)) - return 0; - } - else if (have_lowpc && have_highpc) - { - struct unit_addrs a; - - if (highpc_is_relative) - highpc += lowpc; - a.low = lowpc; - a.high = highpc; - a.u = u; - - if (!add_unit_addr (state, base_address, a, error_callback, data, - addrs)) - return 0; - } - - /* If we found the PC range in the DW_TAG_compile_unit, we - can stop now. */ - if (abbrev->tag == DW_TAG_compile_unit - && (have_ranges || (have_lowpc && have_highpc))) - return 1; - } - - if (abbrev->has_children) - { - if (!find_address_ranges (state, base_address, unit_buf, - dwarf_str, dwarf_str_size, - dwarf_ranges, dwarf_ranges_size, - is_bigendian, error_callback, data, - u, addrs)) - return 0; - } - } - - return 1; -} - -/* Build a mapping from address ranges to the compilation units where - the line number information for that range can be found. Returns 1 - on success, 0 on failure. */ - -static int -build_address_map (struct backtrace_state *state, uintptr_t base_address, - const unsigned char *dwarf_info, size_t dwarf_info_size, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, - const unsigned char *dwarf_str, size_t dwarf_str_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct unit_addrs_vector *addrs) -{ - struct dwarf_buf info; - struct abbrevs abbrevs; - - memset (&addrs->vec, 0, sizeof addrs->vec); - addrs->count = 0; - - /* Read through the .debug_info section. FIXME: Should we use the - .debug_aranges section? gdb and addr2line don't use it, but I'm - not sure why. */ - - info.name = ".debug_info"; - info.start = dwarf_info; - info.buf = dwarf_info; - info.left = dwarf_info_size; - info.is_bigendian = is_bigendian; - info.error_callback = error_callback; - info.data = data; - info.reported_underflow = 0; - - memset (&abbrevs, 0, sizeof abbrevs); - while (info.left > 0) - { - const unsigned char *unit_data_start; - uint64_t len; - int is_dwarf64; - struct dwarf_buf unit_buf; - int version; - uint64_t abbrev_offset; - int addrsize; - struct unit *u; - - if (info.reported_underflow) - goto fail; - - unit_data_start = info.buf; - - is_dwarf64 = 0; - len = read_uint32 (&info); - if (len == 0xffffffff) - { - len = read_uint64 (&info); - is_dwarf64 = 1; - } - - unit_buf = info; - unit_buf.left = len; - - if (!advance (&info, len)) - goto fail; - - version = read_uint16 (&unit_buf); - if (version < 2 || version > 4) - { - dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); - goto fail; - } - - abbrev_offset = read_offset (&unit_buf, is_dwarf64); - if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, - is_bigendian, error_callback, data, &abbrevs)) - goto fail; - - addrsize = read_byte (&unit_buf); - - u = ((struct unit *) - backtrace_alloc (state, sizeof *u, error_callback, data)); - if (u == NULL) - goto fail; - u->unit_data = unit_buf.buf; - u->unit_data_len = unit_buf.left; - u->unit_data_offset = unit_buf.buf - unit_data_start; - u->version = version; - u->is_dwarf64 = is_dwarf64; - u->addrsize = addrsize; - u->filename = NULL; - u->comp_dir = NULL; - u->abs_filename = NULL; - u->lineoff = 0; - u->abbrevs = abbrevs; - memset (&abbrevs, 0, sizeof abbrevs); - - /* The actual line number mappings will be read as needed. */ - u->lines = NULL; - u->lines_count = 0; - u->function_addrs = NULL; - u->function_addrs_count = 0; - - if (!find_address_ranges (state, base_address, &unit_buf, - dwarf_str, dwarf_str_size, - dwarf_ranges, dwarf_ranges_size, - is_bigendian, error_callback, data, - u, addrs)) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } - - if (unit_buf.reported_underflow) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } - } - if (info.reported_underflow) - goto fail; - - return 1; - - fail: - free_abbrevs (state, &abbrevs, error_callback, data); - free_unit_addrs_vector (state, addrs, error_callback, data); - return 0; -} - -/* Add a new mapping to the vector of line mappings that we are - building. Returns 1 on success, 0 on failure. */ - -static int -add_line (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, const char *filename, int lineno, - backtrace_error_callback error_callback, void *data, - struct line_vector *vec) -{ - struct line *ln; - - /* If we are adding the same mapping, ignore it. This can happen - when using discriminators. */ - if (vec->count > 0) - { - ln = (struct line *) vec->vec.base + (vec->count - 1); - if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno) - return 1; - } - - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec->vec)); - if (ln == NULL) - return 0; - - /* Add in the base address here, so that we can look up the PC - directly. */ - ln->pc = pc + ddata->base_address; - - ln->filename = filename; - ln->lineno = lineno; - ln->idx = vec->count; - - ++vec->count; - - return 1; -} - -/* Free the line header information. */ - -static void -free_line_header (struct backtrace_state *state, struct line_header *hdr, - backtrace_error_callback error_callback, void *data) -{ - if (hdr->dirs_count != 0) - backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), - error_callback, data); - backtrace_free (state, hdr->filenames, - hdr->filenames_count * sizeof (char *), - error_callback, data); -} - -/* Read the line header. Return 1 on success, 0 on failure. */ - -static int -read_line_header (struct backtrace_state *state, struct unit *u, - int is_dwarf64, struct dwarf_buf *line_buf, - struct line_header *hdr) -{ - uint64_t hdrlen; - struct dwarf_buf hdr_buf; - const unsigned char *p; - const unsigned char *pend; - size_t i; - - hdr->version = read_uint16 (line_buf); - if (hdr->version < 2 || hdr->version > 4) - { - dwarf_buf_error (line_buf, "unsupported line number version"); - return 0; - } - - hdrlen = read_offset (line_buf, is_dwarf64); - - hdr_buf = *line_buf; - hdr_buf.left = hdrlen; - - if (!advance (line_buf, hdrlen)) - return 0; - - hdr->min_insn_len = read_byte (&hdr_buf); - if (hdr->version < 4) - hdr->max_ops_per_insn = 1; - else - hdr->max_ops_per_insn = read_byte (&hdr_buf); - - /* We don't care about default_is_stmt. */ - read_byte (&hdr_buf); - - hdr->line_base = read_sbyte (&hdr_buf); - hdr->line_range = read_byte (&hdr_buf); - - hdr->opcode_base = read_byte (&hdr_buf); - hdr->opcode_lengths = hdr_buf.buf; - if (!advance (&hdr_buf, hdr->opcode_base - 1)) - return 0; - - /* Count the number of directory entries. */ - hdr->dirs_count = 0; - p = hdr_buf.buf; - pend = p + hdr_buf.left; - while (p < pend && *p != '\0') - { - p += strnlen((const char *) p, pend - p) + 1; - ++hdr->dirs_count; - } - - hdr->dirs = NULL; - if (hdr->dirs_count != 0) - { - hdr->dirs = ((const char **) - backtrace_alloc (state, - hdr->dirs_count * sizeof (const char *), - line_buf->error_callback, line_buf->data)); - if (hdr->dirs == NULL) - return 0; - } - - i = 0; - while (*hdr_buf.buf != '\0') - { - if (hdr_buf.reported_underflow) - return 0; - - hdr->dirs[i] = (const char *) hdr_buf.buf; - ++i; - if (!advance (&hdr_buf, - strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) - return 0; - } - if (!advance (&hdr_buf, 1)) - return 0; - - /* Count the number of file entries. */ - hdr->filenames_count = 0; - p = hdr_buf.buf; - pend = p + hdr_buf.left; - while (p < pend && *p != '\0') - { - p += strnlen ((const char *) p, pend - p) + 1; - p += leb128_len (p); - p += leb128_len (p); - p += leb128_len (p); - ++hdr->filenames_count; - } - - hdr->filenames = ((const char **) - backtrace_alloc (state, - hdr->filenames_count * sizeof (char *), - line_buf->error_callback, - line_buf->data)); - if (hdr->filenames == NULL) - return 0; - i = 0; - while (*hdr_buf.buf != '\0') - { - const char *filename; - uint64_t dir_index; - - if (hdr_buf.reported_underflow) - return 0; - - filename = (const char *) hdr_buf.buf; - if (!advance (&hdr_buf, - strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) - return 0; - dir_index = read_uleb128 (&hdr_buf); - if (IS_ABSOLUTE_PATH (filename) - || (dir_index == 0 && u->comp_dir == NULL)) - hdr->filenames[i] = filename; - else - { - const char *dir; - size_t dir_len; - size_t filename_len; - char *s; - - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (line_buf, - ("invalid directory index in " - "line number program header")); - return 0; - } - dir_len = strlen (dir); - filename_len = strlen (filename); - s = ((char *) - backtrace_alloc (state, dir_len + filename_len + 2, - line_buf->error_callback, line_buf->data)); - if (s == NULL) - return 0; - memcpy (s, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, and the - directory or the file name use backslashes, then we - should use a backslash here. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - hdr->filenames[i] = s; - } - - /* Ignore the modification time and size. */ - read_uleb128 (&hdr_buf); - read_uleb128 (&hdr_buf); - - ++i; - } - - if (hdr_buf.reported_underflow) - return 0; - - return 1; -} - -/* Read the line program, adding line mappings to VEC. Return 1 on - success, 0 on failure. */ - -static int -read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, const struct line_header *hdr, - struct dwarf_buf *line_buf, struct line_vector *vec) -{ - uint64_t address; - unsigned int op_index; - const char *reset_filename; - const char *filename; - int lineno; - - address = 0; - op_index = 0; - if (hdr->filenames_count > 0) - reset_filename = hdr->filenames[0]; - else - reset_filename = ""; - filename = reset_filename; - lineno = 1; - while (line_buf->left > 0) - { - unsigned int op; - - op = read_byte (line_buf); - if (op >= hdr->opcode_base) - { - unsigned int advance; - - /* Special opcode. */ - op -= hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - lineno += hdr->line_base + (int) (op % hdr->line_range); - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - } - else if (op == DW_LNS_extended_op) - { - uint64_t len; - - len = read_uleb128 (line_buf); - op = read_byte (line_buf); - switch (op) - { - case DW_LNE_end_sequence: - /* FIXME: Should we mark the high PC here? It seems - that we already have that information from the - compilation unit. */ - address = 0; - op_index = 0; - filename = reset_filename; - lineno = 1; - break; - case DW_LNE_set_address: - address = read_address (line_buf, u->addrsize); - break; - case DW_LNE_define_file: - { - const char *f; - unsigned int dir_index; - - f = (const char *) line_buf->buf; - if (!advance (line_buf, strnlen (f, line_buf->left) + 1)) - return 0; - dir_index = read_uleb128 (line_buf); - /* Ignore that time and length. */ - read_uleb128 (line_buf); - read_uleb128 (line_buf); - if (IS_ABSOLUTE_PATH (f)) - filename = f; - else - { - const char *dir; - size_t dir_len; - size_t f_len; - char *p; - - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (line_buf, - ("invalid directory index " - "in line number program")); - return 0; - } - dir_len = strlen (dir); - f_len = strlen (f); - p = ((char *) - backtrace_alloc (state, dir_len + f_len + 2, - line_buf->error_callback, - line_buf->data)); - if (p == NULL) - return 0; - memcpy (p, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, - and the directory or the file name use - backslashes, then we should use a backslash - here. */ - p[dir_len] = '/'; - memcpy (p + dir_len + 1, f, f_len + 1); - filename = p; - } - } - break; -#ifdef DW_LNE_set_discriminator - case DW_LNE_set_discriminator: - /* We don't care about discriminators. */ - read_uleb128 (line_buf); - break; -#endif - default: - if (!advance (line_buf, len - 1)) - return 0; - break; - } - } - else - { - switch (op) - { - case DW_LNS_copy: - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - break; - case DW_LNS_advance_pc: - { - uint64_t advance; - - advance = read_uleb128 (line_buf); - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_advance_line: - lineno += (int) read_sleb128 (line_buf); - break; - case DW_LNS_set_file: - { - uint64_t fileno; - - fileno = read_uleb128 (line_buf); - if (fileno == 0) - filename = ""; - else - { - if (fileno - 1 >= hdr->filenames_count) - { - dwarf_buf_error (line_buf, - ("invalid file number in " - "line number program")); - return 0; - } - filename = hdr->filenames[fileno - 1]; - } - } - break; - case DW_LNS_set_column: - read_uleb128 (line_buf); - break; - case DW_LNS_negate_stmt: - break; - case DW_LNS_set_basic_block: - break; - case DW_LNS_const_add_pc: - { - unsigned int advance; - - op = 255 - hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_fixed_advance_pc: - address += read_uint16 (line_buf); - op_index = 0; - break; - case DW_LNS_set_prologue_end: - break; - case DW_LNS_set_epilogue_begin: - break; - case DW_LNS_set_isa: - read_uleb128 (line_buf); - break; - default: - { - unsigned int i; - - for (i = hdr->opcode_lengths[op - 1]; i > 0; --i) - read_uleb128 (line_buf); - } - break; - } - } - } - - return 1; -} - -/* Read the line number information for a compilation unit. Returns 1 - on success, 0 on failure. */ - -static int -read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct line_header *hdr, struct line **lines, - size_t *lines_count) -{ - struct line_vector vec; - struct dwarf_buf line_buf; - uint64_t len; - int is_dwarf64; - struct line *ln; - - memset (&vec.vec, 0, sizeof vec.vec); - vec.count = 0; - - memset (hdr, 0, sizeof *hdr); - - if (u->lineoff != (off_t) (size_t) u->lineoff - || (size_t) u->lineoff >= ddata->dwarf_line_size) - { - error_callback (data, "unit line offset out of range", 0); - goto fail; - } - - line_buf.name = ".debug_line"; - line_buf.start = ddata->dwarf_line; - line_buf.buf = ddata->dwarf_line + u->lineoff; - line_buf.left = ddata->dwarf_line_size - u->lineoff; - line_buf.is_bigendian = ddata->is_bigendian; - line_buf.error_callback = error_callback; - line_buf.data = data; - line_buf.reported_underflow = 0; - - is_dwarf64 = 0; - len = read_uint32 (&line_buf); - if (len == 0xffffffff) - { - len = read_uint64 (&line_buf); - is_dwarf64 = 1; - } - line_buf.left = len; - - if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr)) - goto fail; - - if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) - goto fail; - - if (line_buf.reported_underflow) - goto fail; - - if (vec.count == 0) - { - /* This is not a failure in the sense of a generating an error, - but it is a failure in that sense that we have no useful - information. */ - goto fail; - } - - /* Allocate one extra entry at the end. */ - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec.vec)); - if (ln == NULL) - goto fail; - ln->pc = (uintptr_t) -1; - ln->filename = NULL; - ln->lineno = 0; - ln->idx = 0; - - if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) - goto fail; - - ln = (struct line *) vec.vec.base; - backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); - - *lines = ln; - *lines_count = vec.count; - - return 1; - - fail: - vec.vec.alc += vec.vec.size; - vec.vec.size = 0; - backtrace_vector_release (state, &vec.vec, error_callback, data); - free_line_header (state, hdr, error_callback, data); - *lines = (struct line *) (uintptr_t) -1; - *lines_count = 0; - return 0; -} - -/* Read the name of a function from a DIE referenced by a - DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within - the same compilation unit. */ - -static const char * -read_referenced_name (struct dwarf_data *ddata, struct unit *u, - uint64_t offset, backtrace_error_callback error_callback, - void *data) -{ - struct dwarf_buf unit_buf; - uint64_t code; - const struct abbrev *abbrev; - const char *ret; - size_t i; - - /* OFFSET is from the start of the data for this compilation unit. - U->unit_data is the data, but it starts U->unit_data_offset bytes - from the beginning. */ - - if (offset < u->unit_data_offset - || offset - u->unit_data_offset >= u->unit_data_len) - { - error_callback (data, - "abstract origin or specification out of range", - 0); - return NULL; - } - - offset -= u->unit_data_offset; - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_info; - unit_buf.buf = u->unit_data + offset; - unit_buf.left = u->unit_data_len - offset; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - code = read_uleb128 (&unit_buf); - if (code == 0) - { - dwarf_buf_error (&unit_buf, "invalid abstract origin or specification"); - return NULL; - } - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return NULL; - - ret = NULL; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, &unit_buf, - u->is_dwarf64, u->version, u->addrsize, - ddata->dwarf_str, ddata->dwarf_str_size, - &val)) - return NULL; - - switch (abbrev->attrs[i].name) - { - case DW_AT_name: - /* We prefer the linkage name if get one. */ - if (val.encoding == ATTR_VAL_STRING) - ret = val.u.string; - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - if (val.encoding == ATTR_VAL_STRING) - return val.u.string; - break; - - case DW_AT_specification: - if (abbrev->attrs[i].form == DW_FORM_ref_addr - || abbrev->attrs[i].form == DW_FORM_ref_sig8) - { - /* This refers to a specification defined in some other - compilation unit. We can handle this case if we - must, but it's harder. */ - break; - } - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_UNIT) - { - const char *name; - - name = read_referenced_name (ddata, u, val.u.uint, - error_callback, data); - if (name != NULL) - ret = name; - } - break; - - default: - break; - } - } - - return ret; -} - -/* Add a single range to U that maps to function. Returns 1 on - success, 0 on error. */ - -static int -add_function_range (struct backtrace_state *state, struct dwarf_data *ddata, - struct function *function, uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, - void *data, struct function_vector *vec) -{ - struct function_addrs *p; - - /* Add in the base address here, so that we can look up the PC - directly. */ - lowpc += ddata->base_address; - highpc += ddata->base_address; - - if (vec->count > 0) - { - p = (struct function_addrs *) vec->vec.base + vec->count - 1; - if ((lowpc == p->high || lowpc == p->high + 1) - && function == p->function) - { - if (highpc > p->high) - p->high = highpc; - return 1; - } - } - - p = ((struct function_addrs *) - backtrace_vector_grow (state, sizeof (struct function_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - p->low = lowpc; - p->high = highpc; - p->function = function; - ++vec->count; - return 1; -} - -/* Add PC ranges to U that map to FUNCTION. Returns 1 on success, 0 - on error. */ - -static int -add_function_ranges (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, struct function *function, - uint64_t ranges, uint64_t base, - backtrace_error_callback error_callback, void *data, - struct function_vector *vec) -{ - struct dwarf_buf ranges_buf; - - if (ranges >= ddata->dwarf_ranges_size) - { - error_callback (data, "function ranges offset out of range", 0); - return 0; - } - - ranges_buf.name = ".debug_ranges"; - ranges_buf.start = ddata->dwarf_ranges; - ranges_buf.buf = ddata->dwarf_ranges + ranges; - ranges_buf.left = ddata->dwarf_ranges_size - ranges; - ranges_buf.is_bigendian = ddata->is_bigendian; - ranges_buf.error_callback = error_callback; - ranges_buf.data = data; - ranges_buf.reported_underflow = 0; - - while (1) - { - uint64_t low; - uint64_t high; - - if (ranges_buf.reported_underflow) - return 0; - - low = read_address (&ranges_buf, u->addrsize); - high = read_address (&ranges_buf, u->addrsize); - - if (low == 0 && high == 0) - break; - - if (is_highest_address (low, u->addrsize)) - base = high; - else - { - if (!add_function_range (state, ddata, function, low + base, - high + base, error_callback, data, vec)) - return 0; - } - } - - if (ranges_buf.reported_underflow) - return 0; - - return 1; -} - -/* Read one entry plus all its children. Add function addresses to - VEC. Returns 1 on success, 0 on error. */ - -static int -read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct function_vector *vec_function, - struct function_vector *vec_inlined) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - int is_function; - struct function *function; - struct function_vector *vec; - size_t i; - uint64_t lowpc; - int have_lowpc; - uint64_t highpc; - int have_highpc; - int highpc_is_relative; - uint64_t ranges; - int have_ranges; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - is_function = (abbrev->tag == DW_TAG_subprogram - || abbrev->tag == DW_TAG_entry_point - || abbrev->tag == DW_TAG_inlined_subroutine); - - if (abbrev->tag == DW_TAG_inlined_subroutine) - vec = vec_inlined; - else - vec = vec_function; - - function = NULL; - if (is_function) - { - function = ((struct function *) - backtrace_alloc (state, sizeof *function, - error_callback, data)); - if (function == NULL) - return 0; - memset (function, 0, sizeof *function); - } - - lowpc = 0; - have_lowpc = 0; - highpc = 0; - have_highpc = 0; - highpc_is_relative = 0; - ranges = 0; - have_ranges = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, unit_buf, - u->is_dwarf64, u->version, u->addrsize, - ddata->dwarf_str, ddata->dwarf_str_size, - &val)) - return 0; - - /* The compile unit sets the base address for any address - ranges in the function entries. */ - if (abbrev->tag == DW_TAG_compile_unit - && abbrev->attrs[i].name == DW_AT_low_pc - && val.encoding == ATTR_VAL_ADDRESS) - base = val.u.uint; - - if (is_function) - { - switch (abbrev->attrs[i].name) - { - case DW_AT_call_file: - if (val.encoding == ATTR_VAL_UINT) - { - if (val.u.uint == 0) - function->caller_filename = ""; - else - { - if (val.u.uint - 1 >= lhdr->filenames_count) - { - dwarf_buf_error (unit_buf, - ("invalid file number in " - "DW_AT_call_file attribute")); - return 0; - } - function->caller_filename = - lhdr->filenames[val.u.uint - 1]; - } - } - break; - - case DW_AT_call_line: - if (val.encoding == ATTR_VAL_UINT) - function->caller_lineno = val.u.uint; - break; - - case DW_AT_abstract_origin: - case DW_AT_specification: - if (abbrev->attrs[i].form == DW_FORM_ref_addr - || abbrev->attrs[i].form == DW_FORM_ref_sig8) - { - /* This refers to an abstract origin defined in - some other compilation unit. We can handle - this case if we must, but it's harder. */ - break; - } - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_UNIT) - { - const char *name; - - name = read_referenced_name (ddata, u, val.u.uint, - error_callback, data); - if (name != NULL) - function->name = name; - } - break; - - case DW_AT_name: - if (val.encoding == ATTR_VAL_STRING) - { - /* Don't override a name we found in some other - way, as it will normally be more - useful--e.g., this name is normally not - mangled. */ - if (function->name == NULL) - function->name = val.u.string; - } - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - if (val.encoding == ATTR_VAL_STRING) - function->name = val.u.string; - break; - - case DW_AT_low_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - lowpc = val.u.uint; - have_lowpc = 1; - } - break; - - case DW_AT_high_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - highpc = val.u.uint; - have_highpc = 1; - } - else if (val.encoding == ATTR_VAL_UINT) - { - highpc = val.u.uint; - have_highpc = 1; - highpc_is_relative = 1; - } - break; - - case DW_AT_ranges: - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION) - { - ranges = val.u.uint; - have_ranges = 1; - } - break; - - default: - break; - } - } - } - - /* If we couldn't find a name for the function, we have no use - for it. */ - if (is_function && function->name == NULL) - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - - if (is_function) - { - if (have_ranges) - { - if (!add_function_ranges (state, ddata, u, function, ranges, - base, error_callback, data, vec)) - return 0; - } - else if (have_lowpc && have_highpc) - { - if (highpc_is_relative) - highpc += lowpc; - if (!add_function_range (state, ddata, function, lowpc, highpc, - error_callback, data, vec)) - return 0; - } - else - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - } - - if (abbrev->has_children) - { - if (!is_function) - { - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - vec_inlined)) - return 0; - } - else - { - struct function_vector fvec; - - /* Gather any information for inlined functions in - FVEC. */ - - memset (&fvec, 0, sizeof fvec); - - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - &fvec)) - return 0; - - if (fvec.count > 0) - { - struct function_addrs *faddrs; - - if (!backtrace_vector_release (state, &fvec.vec, - error_callback, data)) - return 0; - - faddrs = (struct function_addrs *) fvec.vec.base; - backtrace_qsort (faddrs, fvec.count, - sizeof (struct function_addrs), - function_addrs_compare); - - function->function_addrs = faddrs; - function->function_addrs_count = fvec.count; - } - } - } - } - - return 1; -} - -/* Read function name information for a compilation unit. We look - through the whole unit looking for function tags. */ - -static void -read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct function_vector *fvec, - struct function_addrs **ret_addrs, - size_t *ret_addrs_count) -{ - struct function_vector lvec; - struct function_vector *pfvec; - struct dwarf_buf unit_buf; - struct function_addrs *addrs; - size_t addrs_count; - - /* Use FVEC if it is not NULL. Otherwise use our own vector. */ - if (fvec != NULL) - pfvec = fvec; - else - { - memset (&lvec, 0, sizeof lvec); - pfvec = &lvec; - } - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_info; - unit_buf.buf = u->unit_data; - unit_buf.left = u->unit_data_len; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - while (unit_buf.left > 0) - { - if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, - error_callback, data, pfvec, pfvec)) - return; - } - - if (pfvec->count == 0) - return; - - addrs_count = pfvec->count; - - if (fvec == NULL) - { - if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) - return; - addrs = (struct function_addrs *) pfvec->vec.base; - } - else - { - /* Finish this list of addresses, but leave the remaining space in - the vector available for the next function unit. */ - addrs = ((struct function_addrs *) - backtrace_vector_finish (state, &fvec->vec, - error_callback, data)); - if (addrs == NULL) - return; - fvec->count = 0; - } - - backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), - function_addrs_compare); - - *ret_addrs = addrs; - *ret_addrs_count = addrs_count; -} - -/* See if PC is inlined in FUNCTION. If it is, print out the inlined - information, and update FILENAME and LINENO for the caller. - Returns whatever CALLBACK returns, or 0 to keep going. */ - -static int -report_inlined_functions (uintptr_t pc, struct function *function, - backtrace_full_callback callback, void *data, - const char **filename, int *lineno) -{ - struct function_addrs *function_addrs; - struct function *inlined; - int ret; - - if (function->function_addrs_count == 0) - return 0; - - function_addrs = ((struct function_addrs *) - bsearch (&pc, function->function_addrs, - function->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return 0; - - while (((size_t) (function_addrs - function->function_addrs) + 1 - < function->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - /* We found an inlined call. */ - - inlined = function_addrs->function; - - /* Report any calls inlined into this one. */ - ret = report_inlined_functions (pc, inlined, callback, data, - filename, lineno); - if (ret != 0) - return ret; - - /* Report this inlined call. */ - ret = callback (data, pc, *filename, *lineno, inlined->name); - if (ret != 0) - return ret; - - /* Our caller will report the caller of the inlined function; tell - it the appropriate filename and line number. */ - *filename = inlined->caller_filename; - *lineno = inlined->caller_lineno; - - return 0; -} - -/* Look for a PC in the DWARF mapping for one module. On success, - call CALLBACK and return whatever it returns. On error, call - ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, - 0 if not. */ - -static int -dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data, - int *found) -{ - struct unit_addrs *entry; - struct unit *u; - int new_data; - struct line *lines; - struct line *ln; - struct function_addrs *function_addrs; - struct function *function; - const char *filename; - int lineno; - int ret; - - *found = 1; - - /* Find an address range that includes PC. */ - entry = bsearch (&pc, ddata->addrs, ddata->addrs_count, - sizeof (struct unit_addrs), unit_addrs_search); - - if (entry == NULL) - { - *found = 0; - return 0; - } - - /* If there are multiple ranges that contain PC, use the last one, - in order to produce predictable results. If we assume that all - ranges are properly nested, then the last range will be the - smallest one. */ - while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count - && pc >= (entry + 1)->low - && pc < (entry + 1)->high) - ++entry; - - /* We need the lines, lines_count, function_addrs, - function_addrs_count fields of u. If they are not set, we need - to set them. When running in threaded mode, we need to allow for - the possibility that some other thread is setting them - simultaneously. */ - - u = entry->u; - lines = u->lines; - - /* Skip units with no useful line number information by walking - backward. Useless line number information is marked by setting - lines == -1. */ - while (entry > ddata->addrs - && pc >= (entry - 1)->low - && pc < (entry - 1)->high) - { - if (state->threaded) - lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); - - if (lines != (struct line *) (uintptr_t) -1) - break; - - --entry; - - u = entry->u; - lines = u->lines; - } - - if (state->threaded) - lines = backtrace_atomic_load_pointer (&u->lines); - - new_data = 0; - if (lines == NULL) - { - size_t function_addrs_count; - struct line_header lhdr; - size_t count; - - /* We have never read the line information for this unit. Read - it now. */ - - function_addrs = NULL; - function_addrs_count = 0; - if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr, - &lines, &count)) - { - struct function_vector *pfvec; - - /* If not threaded, reuse DDATA->FVEC for better memory - consumption. */ - if (state->threaded) - pfvec = NULL; - else - pfvec = &ddata->fvec; - read_function_info (state, ddata, &lhdr, error_callback, data, - entry->u, pfvec, &function_addrs, - &function_addrs_count); - free_line_header (state, &lhdr, error_callback, data); - new_data = 1; - } - - /* Atomically store the information we just read into the unit. - If another thread is simultaneously writing, it presumably - read the same information, and we don't care which one we - wind up with; we just leak the other one. We do have to - write the lines field last, so that the acquire-loads above - ensure that the other fields are set. */ - - if (!state->threaded) - { - u->lines_count = count; - u->function_addrs = function_addrs; - u->function_addrs_count = function_addrs_count; - u->lines = lines; - } - else - { - backtrace_atomic_store_size_t (&u->lines_count, count); - backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); - backtrace_atomic_store_size_t (&u->function_addrs_count, - function_addrs_count); - backtrace_atomic_store_pointer (&u->lines, lines); - } - } - - /* Now all fields of U have been initialized. */ - - if (lines == (struct line *) (uintptr_t) -1) - { - /* If reading the line number information failed in some way, - try again to see if there is a better compilation unit for - this PC. */ - if (new_data) - return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, found); - return callback (data, pc, NULL, 0, NULL); - } - - /* Search for PC within this unit. */ - - ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count, - sizeof (struct line), line_search); - if (ln == NULL) - { - /* The PC is between the low_pc and high_pc attributes of the - compilation unit, but no entry in the line table covers it. - This implies that the start of the compilation unit has no - line number information. */ - - if (entry->u->abs_filename == NULL) - { - const char *filename; - - filename = entry->u->filename; - if (filename != NULL - && !IS_ABSOLUTE_PATH (filename) - && entry->u->comp_dir != NULL) - { - size_t filename_len; - const char *dir; - size_t dir_len; - char *s; - - filename_len = strlen (filename); - dir = entry->u->comp_dir; - dir_len = strlen (dir); - s = (char *) backtrace_alloc (state, dir_len + filename_len + 2, - error_callback, data); - if (s == NULL) - { - *found = 0; - return 0; - } - memcpy (s, dir, dir_len); - /* FIXME: Should use backslash if DOS file system. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - filename = s; - } - entry->u->abs_filename = filename; - } - - return callback (data, pc, entry->u->abs_filename, 0, NULL); - } - - /* Search for function name within this unit. */ - - if (entry->u->function_addrs_count == 0) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - function_addrs = ((struct function_addrs *) - bsearch (&pc, entry->u->function_addrs, - entry->u->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - /* If there are multiple function ranges that contain PC, use the - last one, in order to produce predictable results. */ - - while (((size_t) (function_addrs - entry->u->function_addrs + 1) - < entry->u->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - function = function_addrs->function; - - filename = ln->filename; - lineno = ln->lineno; - - ret = report_inlined_functions (pc, function, callback, data, - &filename, &lineno); - if (ret != 0) - return ret; - - return callback (data, pc, filename, lineno, function->name); -} - - -/* Return the file/line information for a PC using the DWARF mapping - we built earlier. */ - -static int -dwarf_fileline (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct dwarf_data *ddata; - int found; - int ret; - - if (!state->threaded) - { - for (ddata = (struct dwarf_data *) state->fileline_data; - ddata != NULL; - ddata = ddata->next) - { - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - } - } - else - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - while (1) - { - ddata = backtrace_atomic_load_pointer (pp); - if (ddata == NULL) - break; - - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - - pp = &ddata->next; - } - } - - /* FIXME: See if any libraries have been dlopen'ed. */ - - return callback (data, pc, NULL, 0, NULL); -} - -/* Initialize our data structures from the DWARF debug info for a - file. Return NULL on failure. */ - -static struct dwarf_data * -build_dwarf_data (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data) -{ - struct unit_addrs_vector addrs_vec; - struct unit_addrs *addrs; - size_t addrs_count; - struct dwarf_data *fdata; - - if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size, - dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges, - dwarf_ranges_size, dwarf_str, dwarf_str_size, - is_bigendian, error_callback, data, &addrs_vec)) - return NULL; - - if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) - return NULL; - addrs = (struct unit_addrs *) addrs_vec.vec.base; - addrs_count = addrs_vec.count; - backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), - unit_addrs_compare); - - fdata = ((struct dwarf_data *) - backtrace_alloc (state, sizeof (struct dwarf_data), - error_callback, data)); - if (fdata == NULL) - return NULL; - - fdata->next = NULL; - fdata->base_address = base_address; - fdata->addrs = addrs; - fdata->addrs_count = addrs_count; - fdata->dwarf_info = dwarf_info; - fdata->dwarf_info_size = dwarf_info_size; - fdata->dwarf_line = dwarf_line; - fdata->dwarf_line_size = dwarf_line_size; - fdata->dwarf_ranges = dwarf_ranges; - fdata->dwarf_ranges_size = dwarf_ranges_size; - fdata->dwarf_str = dwarf_str; - fdata->dwarf_str_size = dwarf_str_size; - fdata->is_bigendian = is_bigendian; - memset (&fdata->fvec, 0, sizeof fdata->fvec); - - return fdata; -} - -/* Build our data structures from the DWARF sections for a module. - Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0 - on failure. */ - -int -backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - struct dwarf_data *fdata; - - fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size, - dwarf_line, dwarf_line_size, dwarf_abbrev, - dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size, - dwarf_str, dwarf_str_size, is_bigendian, - error_callback, data); - if (fdata == NULL) - return 0; - - if (!state->threaded) - { - struct dwarf_data **pp; - - for (pp = (struct dwarf_data **) (void *) &state->fileline_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = fdata; - } - else - { - while (1) - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - - while (1) - { - struct dwarf_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, fdata)) - break; - } - } - - *fileline_fn = dwarf_fileline; - - return 1; -} diff --git a/3rdparty/libbacktrace/elf.c b/3rdparty/libbacktrace/elf.c deleted file mode 100644 index 1a9969cb..00000000 --- a/3rdparty/libbacktrace/elf.c +++ /dev/null @@ -1,3194 +0,0 @@ -/* elf.c -- Get debug data from an ELF file for backtraces. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DL_ITERATE_PHDR -#include -#endif - -#include "backtrace.h" -#include "internal.h" - -#ifndef S_ISLNK - #ifndef S_IFLNK - #define S_IFLNK 0120000 - #endif - #ifndef S_IFMT - #define S_IFMT 0170000 - #endif - #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif - -#ifndef __GNUC__ -#define __builtin_prefetch(p, r, l) -#define unlikely(x) (x) -#else -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN - -/* If strnlen is not declared, provide our own version. */ - -static size_t -xstrnlen (const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; ++i) - if (s[i] == '\0') - break; - return i; -} - -#define strnlen xstrnlen - -#endif - -#ifndef HAVE_LSTAT - -/* Dummy version of lstat for systems that don't have it. */ - -static int -xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED) -{ - return -1; -} - -#define lstat xlstat - -#endif - -#ifndef HAVE_READLINK - -/* Dummy version of readlink for systems that don't have it. */ - -static ssize_t -xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED, - size_t bufsz ATTRIBUTE_UNUSED) -{ - return -1; -} - -#define readlink xreadlink - -#endif - -#ifndef HAVE_DL_ITERATE_PHDR - -/* Dummy version of dl_iterate_phdr for systems that don't have it. */ - -#define dl_phdr_info x_dl_phdr_info -#define dl_iterate_phdr x_dl_iterate_phdr - -struct dl_phdr_info -{ - uintptr_t dlpi_addr; - const char *dlpi_name; -}; - -static int -dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, - size_t, void *) ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - return 0; -} - -#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */ - -/* The configure script must tell us whether we are 32-bit or 64-bit - ELF. We could make this code test and support either possibility, - but there is no point. This code only works for the currently - running executable, which means that we know the ELF mode at - configure time. */ - -#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 -#error "Unknown BACKTRACE_ELF_SIZE" -#endif - -/* might #include which might define our constants - with slightly different values. Undefine them to be safe. */ - -#undef EI_NIDENT -#undef EI_MAG0 -#undef EI_MAG1 -#undef EI_MAG2 -#undef EI_MAG3 -#undef EI_CLASS -#undef EI_DATA -#undef EI_VERSION -#undef ELF_MAG0 -#undef ELF_MAG1 -#undef ELF_MAG2 -#undef ELF_MAG3 -#undef ELFCLASS32 -#undef ELFCLASS64 -#undef ELFDATA2LSB -#undef ELFDATA2MSB -#undef EV_CURRENT -#undef ET_DYN -#undef SHN_LORESERVE -#undef SHN_XINDEX -#undef SHN_UNDEF -#undef SHT_SYMTAB -#undef SHT_STRTAB -#undef SHT_DYNSYM -#undef SHF_COMPRESSED -#undef STT_OBJECT -#undef STT_FUNC -#undef NT_GNU_BUILD_ID -#undef ELFCOMPRESS_ZLIB - -/* Basic types. */ - -typedef uint16_t b_elf_half; /* Elf_Half. */ -typedef uint32_t b_elf_word; /* Elf_Word. */ -typedef int32_t b_elf_sword; /* Elf_Sword. */ - -#if BACKTRACE_ELF_SIZE == 32 - -typedef uint32_t b_elf_addr; /* Elf_Addr. */ -typedef uint32_t b_elf_off; /* Elf_Off. */ - -typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#else - -typedef uint64_t b_elf_addr; /* Elf_Addr. */ -typedef uint64_t b_elf_off; /* Elf_Off. */ -typedef uint64_t b_elf_xword; /* Elf_Xword. */ -typedef int64_t b_elf_sxword; /* Elf_Sxword. */ - -typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#endif - -/* Data structures and associated constants. */ - -#define EI_NIDENT 16 - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - b_elf_half e_type; /* Identifies object file type */ - b_elf_half e_machine; /* Specifies required architecture */ - b_elf_word e_version; /* Identifies object file version */ - b_elf_addr e_entry; /* Entry point virtual address */ - b_elf_off e_phoff; /* Program header table file offset */ - b_elf_off e_shoff; /* Section header table file offset */ - b_elf_word e_flags; /* Processor-specific flags */ - b_elf_half e_ehsize; /* ELF header size in bytes */ - b_elf_half e_phentsize; /* Program header table entry size */ - b_elf_half e_phnum; /* Program header table entry count */ - b_elf_half e_shentsize; /* Section header table entry size */ - b_elf_half e_shnum; /* Section header table entry count */ - b_elf_half e_shstrndx; /* Section header string table index */ -} b_elf_ehdr; /* Elf_Ehdr. */ - -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 - -#define ELFMAG0 0x7f -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' - -#define ELFCLASS32 1 -#define ELFCLASS64 2 - -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_CURRENT 1 - -#define ET_DYN 3 - -typedef struct { - b_elf_word sh_name; /* Section name, index in string tbl */ - b_elf_word sh_type; /* Type of section */ - b_elf_wxword sh_flags; /* Miscellaneous section attributes */ - b_elf_addr sh_addr; /* Section virtual addr at execution */ - b_elf_off sh_offset; /* Section file offset */ - b_elf_wxword sh_size; /* Size of section in bytes */ - b_elf_word sh_link; /* Index of another section */ - b_elf_word sh_info; /* Additional section information */ - b_elf_wxword sh_addralign; /* Section alignment */ - b_elf_wxword sh_entsize; /* Entry size if section holds table */ -} b_elf_shdr; /* Elf_Shdr. */ - -#define SHN_UNDEF 0x0000 /* Undefined section */ -#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ -#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ - -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_DYNSYM 11 - -#define SHF_COMPRESSED 0x800 - -#if BACKTRACE_ELF_SIZE == 32 - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - b_elf_addr st_value; /* Symbol value */ - b_elf_word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ -} b_elf_sym; /* Elf_Sym. */ - -#else /* BACKTRACE_ELF_SIZE != 32 */ - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ - b_elf_addr st_value; /* Symbol value */ - b_elf_xword st_size; /* Symbol size */ -} b_elf_sym; /* Elf_Sym. */ - -#endif /* BACKTRACE_ELF_SIZE != 32 */ - -#define STT_OBJECT 1 -#define STT_FUNC 2 - -typedef struct -{ - uint32_t namesz; - uint32_t descsz; - uint32_t type; - char name[1]; -} b_elf_note; - -#define NT_GNU_BUILD_ID 3 - -#if BACKTRACE_ELF_SIZE == 32 - -typedef struct -{ - b_elf_word ch_type; /* Compresstion algorithm */ - b_elf_word ch_size; /* Uncompressed size */ - b_elf_word ch_addralign; /* Alignment for uncompressed data */ -} b_elf_chdr; /* Elf_Chdr */ - -#else /* BACKTRACE_ELF_SIZE != 32 */ - -typedef struct -{ - b_elf_word ch_type; /* Compression algorithm */ - b_elf_word ch_reserved; /* Reserved */ - b_elf_xword ch_size; /* Uncompressed size */ - b_elf_xword ch_addralign; /* Alignment for uncompressed data */ -} b_elf_chdr; /* Elf_Chdr */ - -#endif /* BACKTRACE_ELF_SIZE != 32 */ - -#define ELFCOMPRESS_ZLIB 1 - -/* An index of ELF sections we care about. */ - -enum debug_section -{ - DEBUG_INFO, - DEBUG_LINE, - DEBUG_ABBREV, - DEBUG_RANGES, - DEBUG_STR, - - /* The old style compressed sections. This list must correspond to - the list of normal debug sections. */ - ZDEBUG_INFO, - ZDEBUG_LINE, - ZDEBUG_ABBREV, - ZDEBUG_RANGES, - ZDEBUG_STR, - - DEBUG_MAX -}; - -/* Names of sections, indexed by enum elf_section. */ - -static const char * const debug_section_names[DEBUG_MAX] = -{ - ".debug_info", - ".debug_line", - ".debug_abbrev", - ".debug_ranges", - ".debug_str", - ".zdebug_info", - ".zdebug_line", - ".zdebug_abbrev", - ".zdebug_ranges", - ".zdebug_str" -}; - -/* Information we gather for the sections we care about. */ - -struct debug_section_info -{ - /* Section file offset. */ - off_t offset; - /* Section size. */ - size_t size; - /* Section contents, after read from file. */ - const unsigned char *data; - /* Whether the SHF_COMPRESSED flag is set for the section. */ - int compressed; -}; - -/* Information we keep for an ELF symbol. */ - -struct elf_symbol -{ - /* The name of the symbol. */ - const char *name; - /* The address of the symbol. */ - uintptr_t address; - /* The size of the symbol. */ - size_t size; -}; - -/* Information to pass to elf_syminfo. */ - -struct elf_syminfo_data -{ - /* Symbols for the next module. */ - struct elf_syminfo_data *next; - /* The ELF symbols, sorted by address. */ - struct elf_symbol *symbols; - /* The number of symbols. */ - size_t count; -}; - -/* Compute the CRC-32 of BUF/LEN. This uses the CRC used for - .gnu_debuglink files. */ - -static uint32_t -elf_crc32 (uint32_t crc, const unsigned char *buf, size_t len) -{ - static const uint32_t crc32_table[256] = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, - 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, - 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, - 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, - 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, - 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, - 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, - 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, - 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, - 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, - 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, - 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, - 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, - 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, - 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, - 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, - 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, - 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, - 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, - 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, - 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, - 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, - 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, - 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, - 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, - 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, - 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, - 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, - 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, - 0x2d02ef8d - }; - const unsigned char *end; - - crc = ~crc; - for (end = buf + len; buf < end; ++ buf) - crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc; -} - -/* Return the CRC-32 of the entire file open at DESCRIPTOR. */ - -static uint32_t -elf_crc32_file (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, void *data) -{ - struct stat st; - struct backtrace_view file_view; - uint32_t ret; - - if (fstat (descriptor, &st) < 0) - { - error_callback (data, "fstat", errno); - return 0; - } - - if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback, - data, &file_view)) - return 0; - - ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size); - - backtrace_release_view (state, &file_view, error_callback, data); - - return ret; -} - -/* A dummy callback function used when we can't find any debug info. */ - -static int -elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in ELF executable", -1); - return 0; -} - -/* A dummy callback function used when we can't find a symbol - table. */ - -void -elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in ELF executable", -1); -} - -/* Compare struct elf_symbol for qsort. */ - -static int -elf_symbol_compare (const void *v1, const void *v2) -{ - const struct elf_symbol *e1 = (const struct elf_symbol *) v1; - const struct elf_symbol *e2 = (const struct elf_symbol *) v2; - - if (e1->address < e2->address) - return -1; - else if (e1->address > e2->address) - return 1; - else - return 0; -} - -/* Compare an ADDR against an elf_symbol for bsearch. We allocate one - extra entry in the array so that this can look safely at the next - entry. */ - -static int -elf_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct elf_symbol *entry = (const struct elf_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->address) - return -1; - else if (addr >= entry->address + entry->size) - return 1; - else - return 0; -} - -/* Initialize the symbol table info for elf_syminfo. */ - -static int -elf_initialize_syminfo (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *symtab_data, size_t symtab_size, - const unsigned char *strtab, size_t strtab_size, - backtrace_error_callback error_callback, - void *data, struct elf_syminfo_data *sdata) -{ - size_t sym_count; - const b_elf_sym *sym; - size_t elf_symbol_count; - size_t elf_symbol_size; - struct elf_symbol *elf_symbols; - size_t i; - unsigned int j; - - sym_count = symtab_size / sizeof (b_elf_sym); - - /* We only care about function symbols. Count them. */ - sym = (const b_elf_sym *) symtab_data; - elf_symbol_count = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if ((info == STT_FUNC || info == STT_OBJECT) - && sym->st_shndx != SHN_UNDEF) - ++elf_symbol_count; - } - - elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); - elf_symbols = ((struct elf_symbol *) - backtrace_alloc (state, elf_symbol_size, error_callback, - data)); - if (elf_symbols == NULL) - return 0; - - sym = (const b_elf_sym *) symtab_data; - j = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if (info != STT_FUNC && info != STT_OBJECT) - continue; - if (sym->st_shndx == SHN_UNDEF) - continue; - if (sym->st_name >= strtab_size) - { - error_callback (data, "symbol string index out of range", 0); - backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, - data); - return 0; - } - elf_symbols[j].name = (const char *) strtab + sym->st_name; - elf_symbols[j].address = sym->st_value + base_address; - elf_symbols[j].size = sym->st_size; - ++j; - } - - backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), - elf_symbol_compare); - - sdata->next = NULL; - sdata->symbols = elf_symbols; - sdata->count = elf_symbol_count; - - return 1; -} - -/* Add EDATA to the list in STATE. */ - -static void -elf_add_syminfo_data (struct backtrace_state *state, - struct elf_syminfo_data *edata) -{ - if (!state->threaded) - { - struct elf_syminfo_data **pp; - - for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = edata; - } - else - { - while (1) - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct elf_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, edata)) - break; - } - } -} - -/* Return the symbol name and value for an ADDR. */ - -void -elf_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct elf_syminfo_data *edata; - struct elf_symbol *sym = NULL; - - if (!state->threaded) - { - for (edata = (struct elf_syminfo_data *) state->syminfo_data; - edata != NULL; - edata = edata->next) - { - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - } - } - else - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - edata = backtrace_atomic_load_pointer (pp); - if (edata == NULL) - break; - - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - - pp = &edata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->address, sym->size); -} - -/* Return whether FILENAME is a symlink. */ - -static int -elf_is_symlink (const char *filename) -{ - struct stat st; - - if (lstat (filename, &st) < 0) - return 0; - return S_ISLNK (st.st_mode); -} - -/* Return the results of reading the symlink FILENAME in a buffer - allocated by backtrace_alloc. Return the length of the buffer in - *LEN. */ - -static char * -elf_readlink (struct backtrace_state *state, const char *filename, - backtrace_error_callback error_callback, void *data, - size_t *plen) -{ - size_t len; - char *buf; - - len = 128; - while (1) - { - ssize_t rl; - - buf = backtrace_alloc (state, len, error_callback, data); - if (buf == NULL) - return NULL; - rl = readlink (filename, buf, len); - if (rl < 0) - { - backtrace_free (state, buf, len, error_callback, data); - return NULL; - } - if ((size_t) rl < len - 1) - { - buf[rl] = '\0'; - *plen = len; - return buf; - } - backtrace_free (state, buf, len, error_callback, data); - len *= 2; - } -} - -/* Open a separate debug info file, using the build ID to find it. - Returns an open file descriptor, or -1. - - The GDB manual says that the only place gdb looks for a debug file - when the build ID is known is in /usr/lib/debug/.build-id. */ - -static int -elf_open_debugfile_by_buildid (struct backtrace_state *state, - const char *buildid_data, size_t buildid_size, - backtrace_error_callback error_callback, - void *data) -{ - const char * const prefix = "/usr/lib/debug/.build-id/"; - const size_t prefix_len = strlen (prefix); - const char * const suffix = ".debug"; - const size_t suffix_len = strlen (suffix); - size_t len; - char *bd_filename; - char *t; - size_t i; - int ret; - int does_not_exist; - - len = prefix_len + buildid_size * 2 + suffix_len + 2; - bd_filename = backtrace_alloc (state, len, error_callback, data); - if (bd_filename == NULL) - return -1; - - t = bd_filename; - memcpy (t, prefix, prefix_len); - t += prefix_len; - for (i = 0; i < buildid_size; i++) - { - unsigned char b; - unsigned char nib; - - b = (unsigned char) buildid_data[i]; - nib = (b & 0xf0) >> 4; - *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; - nib = b & 0x0f; - *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10; - if (i == 0) - *t++ = '/'; - } - memcpy (t, suffix, suffix_len); - t[suffix_len] = '\0'; - - ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist); - - backtrace_free (state, bd_filename, len, error_callback, data); - - /* gdb checks that the debuginfo file has the same build ID note. - That seems kind of pointless to me--why would it have the right - name but not the right build ID?--so skipping the check. */ - - return ret; -} - -/* Try to open a file whose name is PREFIX (length PREFIX_LEN) - concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with - DEBUGLINK_NAME. Returns an open file descriptor, or -1. */ - -static int -elf_try_debugfile (struct backtrace_state *state, const char *prefix, - size_t prefix_len, const char *prefix2, size_t prefix2_len, - const char *debuglink_name, - backtrace_error_callback error_callback, void *data) -{ - size_t debuglink_len; - size_t try_len; - char *try; - int does_not_exist; - int ret; - - debuglink_len = strlen (debuglink_name); - try_len = prefix_len + prefix2_len + debuglink_len + 1; - try = backtrace_alloc (state, try_len, error_callback, data); - if (try == NULL) - return -1; - - memcpy (try, prefix, prefix_len); - memcpy (try + prefix_len, prefix2, prefix2_len); - memcpy (try + prefix_len + prefix2_len, debuglink_name, debuglink_len); - try[prefix_len + prefix2_len + debuglink_len] = '\0'; - - ret = backtrace_open (try, error_callback, data, &does_not_exist); - - backtrace_free (state, try, try_len, error_callback, data); - - return ret; -} - -/* Find a separate debug info file, using the debuglink section data - to find it. Returns an open file descriptor, or -1. */ - -static int -elf_find_debugfile_by_debuglink (struct backtrace_state *state, - const char *filename, - const char *debuglink_name, - backtrace_error_callback error_callback, - void *data) -{ - int ret; - char *alc; - size_t alc_len; - const char *slash; - int ddescriptor; - const char *prefix; - size_t prefix_len; - - /* Resolve symlinks in FILENAME. Since FILENAME is fairly likely to - be /proc/self/exe, symlinks are common. We don't try to resolve - the whole path name, just the base name. */ - ret = -1; - alc = NULL; - alc_len = 0; - while (elf_is_symlink (filename)) - { - char *new_buf; - size_t new_len; - - new_buf = elf_readlink (state, filename, error_callback, data, &new_len); - if (new_buf == NULL) - break; - - if (new_buf[0] == '/') - filename = new_buf; - else - { - slash = strrchr (filename, '/'); - if (slash == NULL) - filename = new_buf; - else - { - size_t clen; - char *c; - - slash++; - clen = slash - filename + strlen (new_buf) + 1; - c = backtrace_alloc (state, clen, error_callback, data); - if (c == NULL) - goto done; - - memcpy (c, filename, slash - filename); - memcpy (c + (slash - filename), new_buf, strlen (new_buf)); - c[slash - filename + strlen (new_buf)] = '\0'; - backtrace_free (state, new_buf, new_len, error_callback, data); - filename = c; - new_buf = c; - new_len = clen; - } - } - - if (alc != NULL) - backtrace_free (state, alc, alc_len, error_callback, data); - alc = new_buf; - alc_len = new_len; - } - - /* Look for DEBUGLINK_NAME in the same directory as FILENAME. */ - - slash = strrchr (filename, '/'); - if (slash == NULL) - { - prefix = ""; - prefix_len = 0; - } - else - { - slash++; - prefix = filename; - prefix_len = slash - filename; - } - - ddescriptor = elf_try_debugfile (state, prefix, prefix_len, "", 0, - debuglink_name, error_callback, data); - if (ddescriptor >= 0) - { - ret = ddescriptor; - goto done; - } - - /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME. */ - - ddescriptor = elf_try_debugfile (state, prefix, prefix_len, ".debug/", - strlen (".debug/"), debuglink_name, - error_callback, data); - if (ddescriptor >= 0) - { - ret = ddescriptor; - goto done; - } - - /* Look for DEBUGLINK_NAME in /usr/lib/debug. */ - - ddescriptor = elf_try_debugfile (state, "/usr/lib/debug/", - strlen ("/usr/lib/debug/"), prefix, - prefix_len, debuglink_name, - error_callback, data); - if (ddescriptor >= 0) - ret = ddescriptor; - - done: - if (alc != NULL && alc_len > 0) - backtrace_free (state, alc, alc_len, error_callback, data); - return ret; -} - -/* Open a separate debug info file, using the debuglink section data - to find it. Returns an open file descriptor, or -1. */ - -static int -elf_open_debugfile_by_debuglink (struct backtrace_state *state, - const char *filename, - const char *debuglink_name, - uint32_t debuglink_crc, - backtrace_error_callback error_callback, - void *data) -{ - int ddescriptor; - uint32_t got_crc; - - ddescriptor = elf_find_debugfile_by_debuglink (state, filename, - debuglink_name, - error_callback, data); - if (ddescriptor < 0) - return -1; - - // HEAPTRACK: only compare crc if available - got_crc = debuglink_crc ? elf_crc32_file (state, ddescriptor, error_callback, data) : 0; - if (got_crc != debuglink_crc) - { - backtrace_close (ddescriptor, error_callback, data); - return -1; - } - - return ddescriptor; -} - -/* A function useful for setting a breakpoint for an inflation failure - when this code is compiled with -g. */ - -static void -elf_zlib_failed(void) -{ -} - -/* *PVAL is the current value being read from the stream, and *PBITS - is the number of valid bits. Ensure that *PVAL holds at least 15 - bits by reading additional bits from *PPIN, up to PINEND, as - needed. Updates *PPIN, *PVAL and *PBITS. Returns 1 on success, 0 - on error. */ - -static int -elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend, - uint64_t *pval, unsigned int *pbits) -{ - unsigned int bits; - const unsigned char *pin; - uint64_t val; - uint32_t next; - - bits = *pbits; - if (bits >= 15) - return 1; - pin = *ppin; - val = *pval; - - if (unlikely (pinend - pin < 4)) - { - elf_zlib_failed (); - return 0; - } - - /* We've ensured that PIN is aligned. */ - next = *(const uint32_t *)pin; - -#if __BYTE_ORDER == __ORDER_BIG_ENDIAN - next = __builtin_bswap32 (next); -#endif - - val |= (uint64_t)next << bits; - bits += 32; - pin += 4; - - /* We will need the next four bytes soon. */ - __builtin_prefetch (pin, 0, 0); - - *ppin = pin; - *pval = val; - *pbits = bits; - return 1; -} - -/* Huffman code tables, like the rest of the zlib format, are defined - by RFC 1951. We store a Huffman code table as a series of tables - stored sequentially in memory. Each entry in a table is 16 bits. - The first, main, table has 256 entries. It is followed by a set of - secondary tables of length 2 to 128 entries. The maximum length of - a code sequence in the deflate format is 15 bits, so that is all we - need. Each secondary table has an index, which is the offset of - the table in the overall memory storage. - - The deflate format says that all codes of a given bit length are - lexicographically consecutive. Perhaps we could have 130 values - that require a 15-bit code, perhaps requiring three secondary - tables of size 128. I don't know if this is actually possible, but - it suggests that the maximum size required for secondary tables is - 3 * 128 + 3 * 64 ... == 768. The zlib enough program reports 660 - as the maximum. We permit 768, since in addition to the 256 for - the primary table, with two bytes per entry, and with the two - tables we need, that gives us a page. - - A single table entry needs to store a value or (for the main table - only) the index and size of a secondary table. Values range from 0 - to 285, inclusive. Secondary table indexes, per above, range from - 0 to 510. For a value we need to store the number of bits we need - to determine that value (one value may appear multiple times in the - table), which is 1 to 8. For a secondary table we need to store - the number of bits used to index into the table, which is 1 to 7. - And of course we need 1 bit to decide whether we have a value or a - secondary table index. So each entry needs 9 bits for value/table - index, 3 bits for size, 1 bit what it is. For simplicity we use 16 - bits per entry. */ - -/* Number of entries we allocate to for one code table. We get a page - for the two code tables we need. */ - -#define HUFFMAN_TABLE_SIZE (1024) - -/* Bit masks and shifts for the values in the table. */ - -#define HUFFMAN_VALUE_MASK 0x01ff -#define HUFFMAN_BITS_SHIFT 9 -#define HUFFMAN_BITS_MASK 0x7 -#define HUFFMAN_SECONDARY_SHIFT 12 - -/* For working memory while inflating we need two code tables, we need - an array of code lengths (max value 15, so we use unsigned char), - and an array of unsigned shorts used while building a table. The - latter two arrays must be large enough to hold the maximum number - of code lengths, which RFC 1951 defines as 286 + 30. */ - -#define ZDEBUG_TABLE_SIZE \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ - + (286 + 30) * sizeof (uint16_t) \ - + (286 + 30) * sizeof (unsigned char)) - -#define ZDEBUG_TABLE_CODELEN_OFFSET \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \ - + (286 + 30) * sizeof (uint16_t)) - -#define ZDEBUG_TABLE_WORK_OFFSET \ - (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t)) - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - -/* Used by the main function that generates the fixed table to learn - the table size. */ -static size_t final_next_secondary; - -#endif - -/* Build a Huffman code table from an array of lengths in CODES of - length CODES_LEN. The table is stored into *TABLE. ZDEBUG_TABLE - is the same as for elf_zlib_inflate, used to find some work space. - Returns 1 on success, 0 on error. */ - -static int -elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, - uint16_t *zdebug_table, uint16_t *table) -{ - uint16_t count[16]; - uint16_t start[16]; - uint16_t prev[16]; - uint16_t firstcode[7]; - uint16_t *next; - size_t i; - size_t j; - unsigned int code; - size_t next_secondary; - - /* Count the number of code of each length. Set NEXT[val] to be the - next value after VAL with the same bit length. */ - - next = (uint16_t *) (((unsigned char *) zdebug_table) - + ZDEBUG_TABLE_WORK_OFFSET); - - memset (&count[0], 0, 16 * sizeof (uint16_t)); - for (i = 0; i < codes_len; ++i) - { - if (unlikely (codes[i] >= 16)) - { - elf_zlib_failed (); - return 0; - } - - if (count[codes[i]] == 0) - { - start[codes[i]] = i; - prev[codes[i]] = i; - } - else - { - next[prev[codes[i]]] = i; - prev[codes[i]] = i; - } - - ++count[codes[i]]; - } - - /* For each length, fill in the table for the codes of that - length. */ - - memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t)); - - /* Handle the values that do not require a secondary table. */ - - code = 0; - for (j = 1; j <= 8; ++j) - { - unsigned int jcnt; - unsigned int val; - - jcnt = count[j]; - if (jcnt == 0) - continue; - - if (unlikely (jcnt > (1U << j))) - { - elf_zlib_failed (); - return 0; - } - - /* There are JCNT values that have this length, the values - starting from START[j] continuing through NEXT[VAL]. Those - values are assigned consecutive values starting at CODE. */ - - val = start[j]; - for (i = 0; i < jcnt; ++i) - { - uint16_t tval; - size_t ind; - unsigned int incr; - - /* In the compressed bit stream, the value VAL is encoded as - J bits with the value C. */ - - if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0)) - { - elf_zlib_failed (); - return 0; - } - - tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT); - - /* The table lookup uses 8 bits. If J is less than 8, we - don't know what the other bits will be. We need to fill - in all possibilities in the table. Since the Huffman - code is unambiguous, those entries can't be used for any - other code. */ - - for (ind = code; ind < 0x100; ind += 1 << j) - { - if (unlikely (table[ind] != 0)) - { - elf_zlib_failed (); - return 0; - } - table[ind] = tval; - } - - /* Advance to the next value with this length. */ - if (i + 1 < jcnt) - val = next[val]; - - /* The Huffman codes are stored in the bitstream with the - most significant bit first, as is required to make them - unambiguous. The effect is that when we read them from - the bitstream we see the bit sequence in reverse order: - the most significant bit of the Huffman code is the least - significant bit of the value we read from the bitstream. - That means that to make our table lookups work, we need - to reverse the bits of CODE. Since reversing bits is - tedious and in general requires using a table, we instead - increment CODE in reverse order. That is, if the number - of bits we are currently using, here named J, is 3, we - count as 000, 100, 010, 110, 001, 101, 011, 111, which is - to say the numbers from 0 to 7 but with the bits - reversed. Going to more bits, aka incrementing J, - effectively just adds more zero bits as the beginning, - and as such does not change the numeric value of CODE. - - To increment CODE of length J in reverse order, find the - most significant zero bit and set it to one while - clearing all higher bits. In other words, add 1 modulo - 2^J, only reversed. */ - - incr = 1U << (j - 1); - while ((code & incr) != 0) - incr >>= 1; - if (incr == 0) - code = 0; - else - { - code &= incr - 1; - code += incr; - } - } - } - - /* Handle the values that require a secondary table. */ - - /* Set FIRSTCODE, the number at which the codes start, for each - length. */ - - for (j = 9; j < 16; j++) - { - unsigned int jcnt; - unsigned int k; - - jcnt = count[j]; - if (jcnt == 0) - continue; - - /* There are JCNT values that have this length, the values - starting from START[j]. Those values are assigned - consecutive values starting at CODE. */ - - firstcode[j - 9] = code; - - /* Reverse add JCNT to CODE modulo 2^J. */ - for (k = 0; k < j; ++k) - { - if ((jcnt & (1U << k)) != 0) - { - unsigned int m; - unsigned int bit; - - bit = 1U << (j - k - 1); - for (m = 0; m < j - k; ++m, bit >>= 1) - { - if ((code & bit) == 0) - { - code += bit; - break; - } - code &= ~bit; - } - jcnt &= ~(1U << k); - } - } - if (unlikely (jcnt != 0)) - { - elf_zlib_failed (); - return 0; - } - } - - /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive - values starting at START[J] with consecutive codes starting at - FIRSTCODE[J - 9]. In the primary table we need to point to the - secondary table, and the secondary table will be indexed by J - 9 - bits. We count down from 15 so that we install the larger - secondary tables first, as the smaller ones may be embedded in - the larger ones. */ - - next_secondary = 0; /* Index of next secondary table (after primary). */ - for (j = 15; j >= 9; j--) - { - unsigned int jcnt; - unsigned int val; - size_t primary; /* Current primary index. */ - size_t secondary; /* Offset to current secondary table. */ - size_t secondary_bits; /* Bit size of current secondary table. */ - - jcnt = count[j]; - if (jcnt == 0) - continue; - - val = start[j]; - code = firstcode[j - 9]; - primary = 0x100; - secondary = 0; - secondary_bits = 0; - for (i = 0; i < jcnt; ++i) - { - uint16_t tval; - size_t ind; - unsigned int incr; - - if ((code & 0xff) != primary) - { - uint16_t tprimary; - - /* Fill in a new primary table entry. */ - - primary = code & 0xff; - - tprimary = table[primary]; - if (tprimary == 0) - { - /* Start a new secondary table. */ - - if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK) - != next_secondary)) - { - elf_zlib_failed (); - return 0; - } - - secondary = next_secondary; - secondary_bits = j - 8; - next_secondary += 1 << secondary_bits; - table[primary] = (secondary - + ((j - 8) << HUFFMAN_BITS_SHIFT) - + (1U << HUFFMAN_SECONDARY_SHIFT)); - } - else - { - /* There is an existing entry. It had better be a - secondary table with enough bits. */ - if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT)) - == 0)) - { - elf_zlib_failed (); - return 0; - } - secondary = tprimary & HUFFMAN_VALUE_MASK; - secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT) - & HUFFMAN_BITS_MASK); - if (unlikely (secondary_bits < j - 8)) - { - elf_zlib_failed (); - return 0; - } - } - } - - /* Fill in secondary table entries. */ - - tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT); - - for (ind = code >> 8; - ind < (1U << secondary_bits); - ind += 1U << (j - 8)) - { - if (unlikely (table[secondary + 0x100 + ind] != 0)) - { - elf_zlib_failed (); - return 0; - } - table[secondary + 0x100 + ind] = tval; - } - - if (i + 1 < jcnt) - val = next[val]; - - incr = 1U << (j - 1); - while ((code & incr) != 0) - incr >>= 1; - if (incr == 0) - code = 0; - else - { - code &= incr - 1; - code += incr; - } - } - } - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - final_next_secondary = next_secondary; -#endif - - return 1; -} - -#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE - -/* Used to generate the fixed Huffman table for block type 1. */ - -#include - -static uint16_t table[ZDEBUG_TABLE_SIZE]; -static unsigned char codes[287]; - -int -main () -{ - size_t i; - - for (i = 0; i <= 143; ++i) - codes[i] = 8; - for (i = 144; i <= 255; ++i) - codes[i] = 9; - for (i = 256; i <= 279; ++i) - codes[i] = 7; - for (i = 280; i <= 287; ++i) - codes[i] = 8; - if (!elf_zlib_inflate_table (&codes[0], 287, &table[0], &table[0])) - { - fprintf (stderr, "elf_zlib_inflate_table failed\n"); - exit (EXIT_FAILURE); - } - - printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n", - final_next_secondary + 0x100); - printf ("{\n"); - for (i = 0; i < final_next_secondary + 0x100; i += 8) - { - size_t j; - - printf (" "); - for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) - printf (" %#x,", table[j]); - printf ("\n"); - } - printf ("};\n"); - return 0; -} - -#endif - -/* The fixed table generated by the #ifdef'ed out main function - above. */ - -static const uint16_t elf_zlib_default_table[0x170] = -{ - 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1232, - 0xd08, 0xe60, 0xe20, 0x1212, 0xe00, 0xe80, 0xe40, 0x1252, - 0xd04, 0xe58, 0xe18, 0x1202, 0xd14, 0xe78, 0xe38, 0x1242, - 0xd0c, 0xe68, 0xe28, 0x1222, 0xe08, 0xe88, 0xe48, 0x1262, - 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x123a, - 0xd0a, 0xe64, 0xe24, 0x121a, 0xe04, 0xe84, 0xe44, 0x125a, - 0xd06, 0xe5c, 0xe1c, 0x120a, 0xd16, 0xe7c, 0xe3c, 0x124a, - 0xd0e, 0xe6c, 0xe2c, 0x122a, 0xe0c, 0xe8c, 0xe4c, 0x126a, - 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1236, - 0xd09, 0xe62, 0xe22, 0x1216, 0xe02, 0xe82, 0xe42, 0x1256, - 0xd05, 0xe5a, 0xe1a, 0x1206, 0xd15, 0xe7a, 0xe3a, 0x1246, - 0xd0d, 0xe6a, 0xe2a, 0x1226, 0xe0a, 0xe8a, 0xe4a, 0x1266, - 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123e, - 0xd0b, 0xe66, 0xe26, 0x121e, 0xe06, 0xe86, 0xe46, 0x125e, - 0xd07, 0xe5e, 0xe1e, 0x120e, 0xd17, 0xe7e, 0xe3e, 0x124e, - 0xd0f, 0xe6e, 0xe2e, 0x122e, 0xe0e, 0xe8e, 0xe4e, 0x126e, - 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1234, - 0xd08, 0xe61, 0xe21, 0x1214, 0xe01, 0xe81, 0xe41, 0x1254, - 0xd04, 0xe59, 0xe19, 0x1204, 0xd14, 0xe79, 0xe39, 0x1244, - 0xd0c, 0xe69, 0xe29, 0x1224, 0xe09, 0xe89, 0xe49, 0x1264, - 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123c, - 0xd0a, 0xe65, 0xe25, 0x121c, 0xe05, 0xe85, 0xe45, 0x125c, - 0xd06, 0xe5d, 0xe1d, 0x120c, 0xd16, 0xe7d, 0xe3d, 0x124c, - 0xd0e, 0xe6d, 0xe2d, 0x122c, 0xe0d, 0xe8d, 0xe4d, 0x126c, - 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1238, - 0xd09, 0xe63, 0xe23, 0x1218, 0xe03, 0xe83, 0xe43, 0x1258, - 0xd05, 0xe5b, 0xe1b, 0x1208, 0xd15, 0xe7b, 0xe3b, 0x1248, - 0xd0d, 0xe6b, 0xe2b, 0x1228, 0xe0b, 0xe8b, 0xe4b, 0x1268, - 0xd03, 0xe57, 0xe17, 0x1200, 0xd13, 0xe77, 0xe37, 0x1240, - 0xd0b, 0xe67, 0xe27, 0x1220, 0xe07, 0xe87, 0xe47, 0x1260, - 0xd07, 0xe5f, 0xe1f, 0x1210, 0xd17, 0xe7f, 0xe3f, 0x1250, - 0xd0f, 0xe6f, 0xe2f, 0x1230, 0xe0f, 0xe8f, 0xe4f, 0, - 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, - 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, - 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, - 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, - 0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, - 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf, - 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, - 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf, - 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, - 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, - 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, - 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, - 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, - 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff, -}; - -/* Inflate a zlib stream from PIN/SIN to POUT/SOUT. Return 1 on - success, 0 on some error parsing the stream. */ - -static int -elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, - unsigned char *pout, size_t sout) -{ - unsigned char *porigout; - const unsigned char *pinend; - unsigned char *poutend; - - /* We can apparently see multiple zlib streams concatenated - together, so keep going as long as there is something to read. - The last 4 bytes are the checksum. */ - porigout = pout; - pinend = pin + sin; - poutend = pout + sout; - while ((pinend - pin) > 4) - { - uint64_t val; - unsigned int bits; - int last; - - /* Read the two byte zlib header. */ - - if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */ - { - /* Unknown compression method. */ - elf_zlib_failed (); - return 0; - } - if (unlikely ((pin[0] >> 4) > 7)) - { - /* Window size too large. Other than this check, we don't - care about the window size. */ - elf_zlib_failed (); - return 0; - } - if (unlikely ((pin[1] & 0x20) != 0)) - { - /* Stream expects a predefined dictionary, but we have no - dictionary. */ - elf_zlib_failed (); - return 0; - } - val = (pin[0] << 8) | pin[1]; - if (unlikely (val % 31 != 0)) - { - /* Header check failure. */ - elf_zlib_failed (); - return 0; - } - pin += 2; - - /* Align PIN to a 32-bit boundary. */ - - val = 0; - bits = 0; - while ((((uintptr_t) pin) & 3) != 0) - { - val |= (uint64_t)*pin << bits; - bits += 8; - ++pin; - } - - /* Read blocks until one is marked last. */ - - last = 0; - - while (!last) - { - unsigned int type; - const uint16_t *tlit; - const uint16_t *tdist; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - last = val & 1; - type = (val >> 1) & 3; - val >>= 3; - bits -= 3; - - if (unlikely (type == 3)) - { - /* Invalid block type. */ - elf_zlib_failed (); - return 0; - } - - if (type == 0) - { - uint16_t len; - uint16_t lenc; - - /* An uncompressed block. */ - - /* If we've read ahead more than a byte, back up. */ - while (bits > 8) - { - --pin; - bits -= 8; - } - - val = 0; - bits = 0; - if (unlikely ((pinend - pin) < 4)) - { - /* Missing length. */ - elf_zlib_failed (); - return 0; - } - len = pin[0] | (pin[1] << 8); - lenc = pin[2] | (pin[3] << 8); - pin += 4; - lenc = ~lenc; - if (unlikely (len != lenc)) - { - /* Corrupt data. */ - elf_zlib_failed (); - return 0; - } - if (unlikely (len > (unsigned int) (pinend - pin) - || len > (unsigned int) (poutend - pout))) - { - /* Not enough space in buffers. */ - elf_zlib_failed (); - return 0; - } - memcpy (pout, pin, len); - pout += len; - pin += len; - - /* Align PIN. */ - while ((((uintptr_t) pin) & 3) != 0) - { - val |= (uint64_t)*pin << bits; - bits += 8; - ++pin; - } - - /* Go around to read the next block. */ - continue; - } - - if (type == 1) - { - tlit = elf_zlib_default_table; - tdist = elf_zlib_default_table; - } - else - { - unsigned int nlit; - unsigned int ndist; - unsigned int nclen; - unsigned char codebits[19]; - unsigned char *plenbase; - unsigned char *plen; - unsigned char *plenend; - - /* Read a Huffman encoding table. The various magic - numbers here are from RFC 1951. */ - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - nlit = (val & 0x1f) + 257; - val >>= 5; - ndist = (val & 0x1f) + 1; - val >>= 5; - nclen = (val & 0xf) + 4; - val >>= 4; - bits -= 14; - if (unlikely (nlit > 286 || ndist > 30)) - { - /* Values out of range. */ - elf_zlib_failed (); - return 0; - } - - /* Read and build the table used to compress the - literal, length, and distance codes. */ - - memset(&codebits[0], 0, 19); - - /* There are always at least 4 elements in the - table. */ - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[16] = val & 7; - codebits[17] = (val >> 3) & 7; - codebits[18] = (val >> 6) & 7; - codebits[0] = (val >> 9) & 7; - val >>= 12; - bits -= 12; - - if (nclen == 4) - goto codebitsdone; - - codebits[8] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 5) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[7] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 6) - goto codebitsdone; - - codebits[9] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 7) - goto codebitsdone; - - codebits[6] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 8) - goto codebitsdone; - - codebits[10] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 9) - goto codebitsdone; - - codebits[5] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 10) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[11] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 11) - goto codebitsdone; - - codebits[4] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 12) - goto codebitsdone; - - codebits[12] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 13) - goto codebitsdone; - - codebits[3] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 14) - goto codebitsdone; - - codebits[13] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 15) - goto codebitsdone; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - codebits[2] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 16) - goto codebitsdone; - - codebits[14] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 17) - goto codebitsdone; - - codebits[1] = val & 7; - val >>= 3; - bits -= 3; - - if (nclen == 18) - goto codebitsdone; - - codebits[15] = val & 7; - val >>= 3; - bits -= 3; - - codebitsdone: - - if (!elf_zlib_inflate_table (codebits, 19, zdebug_table, - zdebug_table)) - return 0; - - /* Read the compressed bit lengths of the literal, - length, and distance codes. We have allocated space - at the end of zdebug_table to hold them. */ - - plenbase = (((unsigned char *) zdebug_table) - + ZDEBUG_TABLE_CODELEN_OFFSET); - plen = plenbase; - plenend = plen + nlit + ndist; - while (plen < plenend) - { - uint16_t t; - unsigned int b; - uint16_t v; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = zdebug_table[val & 0xff]; - - /* The compression here uses bit lengths up to 7, so - a secondary table is never necessary. */ - if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0)) - { - elf_zlib_failed (); - return 0; - } - - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - val >>= b + 1; - bits -= b + 1; - - v = t & HUFFMAN_VALUE_MASK; - if (v < 16) - *plen++ = v; - else if (v == 16) - { - unsigned int c; - unsigned int prev; - - /* Copy previous entry 3 to 6 times. */ - - if (unlikely (plen == plenbase)) - { - elf_zlib_failed (); - return 0; - } - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 3 + (val & 0x3); - val >>= 2; - bits -= 2; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - prev = plen[-1]; - switch (c) - { - case 6: - *plen++ = prev; - /* fallthrough */ - case 5: - *plen++ = prev; - /* fallthrough */ - case 4: - *plen++ = prev; - } - *plen++ = prev; - *plen++ = prev; - *plen++ = prev; - } - else if (v == 17) - { - unsigned int c; - - /* Store zero 3 to 10 times. */ - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 3 + (val & 0x7); - val >>= 3; - bits -= 3; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - switch (c) - { - case 10: - *plen++ = 0; - /* fallthrough */ - case 9: - *plen++ = 0; - /* fallthrough */ - case 8: - *plen++ = 0; - /* fallthrough */ - case 7: - *plen++ = 0; - /* fallthrough */ - case 6: - *plen++ = 0; - /* fallthrough */ - case 5: - *plen++ = 0; - /* fallthrough */ - case 4: - *plen++ = 0; - } - *plen++ = 0; - *plen++ = 0; - *plen++ = 0; - } - else if (v == 18) - { - unsigned int c; - - /* Store zero 11 to 138 times. */ - - /* We used up to 7 bits since the last - elf_zlib_fetch, so we have at least 8 bits - available here. */ - - c = 11 + (val & 0x7f); - val >>= 7; - bits -= 7; - if (unlikely ((unsigned int) (plenend - plen) < c)) - { - elf_zlib_failed (); - return 0; - } - - memset (plen, 0, c); - plen += c; - } - else - { - elf_zlib_failed (); - return 0; - } - } - - /* Make sure that the stop code can appear. */ - - plen = plenbase; - if (unlikely (plen[256] == 0)) - { - elf_zlib_failed (); - return 0; - } - - /* Build the decompression tables. */ - - if (!elf_zlib_inflate_table (plen, nlit, zdebug_table, - zdebug_table)) - return 0; - if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table, - zdebug_table + HUFFMAN_TABLE_SIZE)) - return 0; - tlit = zdebug_table; - tdist = zdebug_table + HUFFMAN_TABLE_SIZE; - } - - /* Inflate values until the end of the block. This is the - main loop of the inflation code. */ - - while (1) - { - uint16_t t; - unsigned int b; - uint16_t v; - unsigned int lit; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = tlit[val & 0xff]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - v = t & HUFFMAN_VALUE_MASK; - - if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) - { - lit = v; - val >>= b + 1; - bits -= b + 1; - } - else - { - t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - lit = t & HUFFMAN_VALUE_MASK; - val >>= b + 8; - bits -= b + 8; - } - - if (lit < 256) - { - if (unlikely (pout == poutend)) - { - elf_zlib_failed (); - return 0; - } - - *pout++ = lit; - - /* We will need to write the next byte soon. We ask - for high temporal locality because we will write - to the whole cache line soon. */ - __builtin_prefetch (pout, 1, 3); - } - else if (lit == 256) - { - /* The end of the block. */ - break; - } - else - { - unsigned int dist; - unsigned int len; - - /* Convert lit into a length. */ - - if (lit < 265) - len = lit - 257 + 3; - else if (lit == 285) - len = 258; - else if (unlikely (lit > 285)) - { - elf_zlib_failed (); - return 0; - } - else - { - unsigned int extra; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - /* This is an expression for the table of length - codes in RFC 1951 3.2.5. */ - lit -= 265; - extra = (lit >> 2) + 1; - len = (lit & 3) << extra; - len += 11; - len += ((1U << (extra - 1)) - 1) << 3; - len += val & ((1U << extra) - 1); - val >>= extra; - bits -= extra; - } - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - t = tdist[val & 0xff]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - v = t & HUFFMAN_VALUE_MASK; - - if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0) - { - dist = v; - val >>= b + 1; - bits -= b + 1; - } - else - { - t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))]; - b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK; - dist = t & HUFFMAN_VALUE_MASK; - val >>= b + 8; - bits -= b + 8; - } - - /* Convert dist to a distance. */ - - if (dist == 0) - { - /* A distance of 1. A common case, meaning - repeat the last character LEN times. */ - - if (unlikely (pout == porigout)) - { - elf_zlib_failed (); - return 0; - } - - if (unlikely ((unsigned int) (poutend - pout) < len)) - { - elf_zlib_failed (); - return 0; - } - - memset (pout, pout[-1], len); - pout += len; - } - else if (unlikely (dist > 29)) - { - elf_zlib_failed (); - return 0; - } - else - { - if (dist < 4) - dist = dist + 1; - else - { - unsigned int extra; - - if (!elf_zlib_fetch (&pin, pinend, &val, &bits)) - return 0; - - /* This is an expression for the table of - distance codes in RFC 1951 3.2.5. */ - dist -= 4; - extra = (dist >> 1) + 1; - dist = (dist & 1) << extra; - dist += 5; - dist += ((1U << (extra - 1)) - 1) << 2; - dist += val & ((1U << extra) - 1); - val >>= extra; - bits -= extra; - } - - /* Go back dist bytes, and copy len bytes from - there. */ - - if (unlikely ((unsigned int) (pout - porigout) < dist)) - { - elf_zlib_failed (); - return 0; - } - - if (unlikely ((unsigned int) (poutend - pout) < len)) - { - elf_zlib_failed (); - return 0; - } - - if (dist >= len) - { - memcpy (pout, pout - dist, len); - pout += len; - } - else - { - while (len > 0) - { - unsigned int copy; - - copy = len < dist ? len : dist; - memcpy (pout, pout - dist, copy); - len -= copy; - pout += copy; - } - } - } - } - } - } - } - - /* We should have filled the output buffer. */ - if (unlikely (pout != poutend)) - { - elf_zlib_failed (); - return 0; - } - - return 1; -} - -/* Verify the zlib checksum. The checksum is in the 4 bytes at - CHECKBYTES, and the uncompressed data is at UNCOMPRESSED / - UNCOMPRESSED_SIZE. Returns 1 on success, 0 on failure. */ - -static int -elf_zlib_verify_checksum (const unsigned char *checkbytes, - const unsigned char *uncompressed, - size_t uncompressed_size) -{ - unsigned int i; - unsigned int cksum; - const unsigned char *p; - uint32_t s1; - uint32_t s2; - size_t hsz; - - cksum = 0; - for (i = 0; i < 4; i++) - cksum = (cksum << 8) | checkbytes[i]; - - s1 = 1; - s2 = 0; - - /* Minimize modulo operations. */ - - p = uncompressed; - hsz = uncompressed_size; - while (hsz >= 5552) - { - for (i = 0; i < 5552; i += 16) - { - /* Manually unroll loop 16 times. */ - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - } - hsz -= 5552; - s1 %= 65521; - s2 %= 65521; - } - - while (hsz >= 16) - { - /* Manually unroll loop 16 times. */ - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - s1 = s1 + *p++; - s2 = s2 + s1; - - hsz -= 16; - } - - for (i = 0; i < hsz; ++i) - { - s1 = s1 + *p++; - s2 = s2 + s1; - } - - s1 %= 65521; - s2 %= 65521; - - if (unlikely ((s2 << 16) + s1 != cksum)) - { - elf_zlib_failed (); - return 0; - } - - return 1; -} - -/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the - checksum. Return 1 on success, 0 on error. */ - -static int -elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin, - uint16_t *zdebug_table, unsigned char *pout, - size_t sout) -{ - if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout)) - return 0; - if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout)) - return 0; - return 1; -} - -/* Uncompress the old compressed debug format, the one emitted by - --compress-debug-sections=zlib-gnu. The compressed data is in - COMPRESSED / COMPRESSED_SIZE, and the function writes to - *UNCOMPRESSED / *UNCOMPRESSED_SIZE. ZDEBUG_TABLE is work space to - hold Huffman tables. Returns 0 on error, 1 on successful - decompression or if something goes wrong. In general we try to - carry on, by returning 1, even if we can't decompress. */ - -static int -elf_uncompress_zdebug (struct backtrace_state *state, - const unsigned char *compressed, size_t compressed_size, - uint16_t *zdebug_table, - backtrace_error_callback error_callback, void *data, - unsigned char **uncompressed, size_t *uncompressed_size) -{ - size_t sz; - size_t i; - unsigned char *po; - - *uncompressed = NULL; - *uncompressed_size = 0; - - /* The format starts with the four bytes ZLIB, followed by the 8 - byte length of the uncompressed data in big-endian order, - followed by a zlib stream. */ - - if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0) - return 1; - - sz = 0; - for (i = 0; i < 8; i++) - sz = (sz << 8) | compressed[i + 4]; - - if (*uncompressed != NULL && *uncompressed_size >= sz) - po = *uncompressed; - else - { - po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data); - if (po == NULL) - return 0; - } - - if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12, - zdebug_table, po, sz)) - return 1; - - *uncompressed = po; - *uncompressed_size = sz; - - return 1; -} - -/* Uncompress the new compressed debug format, the official standard - ELF approach emitted by --compress-debug-sections=zlib-gabi. The - compressed data is in COMPRESSED / COMPRESSED_SIZE, and the - function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE. - ZDEBUG_TABLE is work space as for elf_uncompress_zdebug. Returns 0 - on error, 1 on successful decompression or if something goes wrong. - In general we try to carry on, by returning 1, even if we can't - decompress. */ - -static int -elf_uncompress_chdr (struct backtrace_state *state, - const unsigned char *compressed, size_t compressed_size, - uint16_t *zdebug_table, - backtrace_error_callback error_callback, void *data, - unsigned char **uncompressed, size_t *uncompressed_size) -{ - const b_elf_chdr *chdr; - unsigned char *po; - - *uncompressed = NULL; - *uncompressed_size = 0; - - /* The format starts with an ELF compression header. */ - if (compressed_size < sizeof (b_elf_chdr)) - return 1; - - chdr = (const b_elf_chdr *) compressed; - - if (chdr->ch_type != ELFCOMPRESS_ZLIB) - { - /* Unsupported compression algorithm. */ - return 1; - } - - if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size) - po = *uncompressed; - else - { - po = (unsigned char *) backtrace_alloc (state, chdr->ch_size, - error_callback, data); - if (po == NULL) - return 0; - } - - if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr), - compressed_size - sizeof (b_elf_chdr), - zdebug_table, po, chdr->ch_size)) - return 1; - - *uncompressed = po; - *uncompressed_size = chdr->ch_size; - - return 1; -} - -/* This function is a hook for testing the zlib support. It is only - used by tests. */ - -int -backtrace_uncompress_zdebug (struct backtrace_state *state, - const unsigned char *compressed, - size_t compressed_size, - backtrace_error_callback error_callback, - void *data, unsigned char **uncompressed, - size_t *uncompressed_size) -{ - uint16_t *zdebug_table; - int ret; - - zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - return 0; - ret = elf_uncompress_zdebug (state, compressed, compressed_size, - zdebug_table, error_callback, data, - uncompressed, uncompressed_size); - backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, - error_callback, data); - return ret; -} - -/* Add the backtrace data for one ELF file. Returns 1 on success, - 0 on failure (in both cases descriptor is closed) or -1 if exe - is non-zero and the ELF file is ET_DYN, which tells the caller that - elf_add will need to be called on the descriptor again after - base_address is determined. */ - -int -elf_add (struct backtrace_state *state, const char *filename, int descriptor, - uintptr_t base_address, backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, - int exe, int debuginfo) -{ - struct backtrace_view ehdr_view; - b_elf_ehdr ehdr; - off_t shoff; - unsigned int shnum; - unsigned int shstrndx; - struct backtrace_view shdrs_view; - int shdrs_view_valid; - const b_elf_shdr *shdrs; - const b_elf_shdr *shstrhdr; - size_t shstr_size; - off_t shstr_off; - struct backtrace_view names_view; - int names_view_valid; - const char *names; - unsigned int symtab_shndx; - unsigned int dynsym_shndx; - unsigned int i; - struct debug_section_info sections[DEBUG_MAX]; - struct backtrace_view symtab_view; - int symtab_view_valid; - struct backtrace_view strtab_view; - int strtab_view_valid; - struct backtrace_view buildid_view; - int buildid_view_valid; - const char *buildid_data; - uint32_t buildid_size; - struct backtrace_view debuglink_view; - int debuglink_view_valid; - const char *debuglink_name; - uint32_t debuglink_crc; - off_t min_offset; - off_t max_offset; - struct backtrace_view debug_view; - int debug_view_valid; - unsigned int using_debug_view; - uint16_t *zdebug_table; - - *found_sym = 0; - *found_dwarf = 0; - - shdrs_view_valid = 0; - names_view_valid = 0; - symtab_view_valid = 0; - strtab_view_valid = 0; - buildid_view_valid = 0; - buildid_data = NULL; - buildid_size = 0; - debuglink_view_valid = 0; - debuglink_name = NULL; - debuglink_crc = 0; - debug_view_valid = 0; - - if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, - data, &ehdr_view)) - goto fail; - - memcpy (&ehdr, ehdr_view.data, sizeof ehdr); - - backtrace_release_view (state, &ehdr_view, error_callback, data); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0 - || ehdr.e_ident[EI_MAG1] != ELFMAG1 - || ehdr.e_ident[EI_MAG2] != ELFMAG2 - || ehdr.e_ident[EI_MAG3] != ELFMAG3) - { - error_callback (data, "executable file is not ELF", 0); - goto fail; - } - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) - { - error_callback (data, "executable file is unrecognized ELF version", 0); - goto fail; - } - -#if BACKTRACE_ELF_SIZE == 32 -#define BACKTRACE_ELFCLASS ELFCLASS32 -#else -#define BACKTRACE_ELFCLASS ELFCLASS64 -#endif - - if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) - { - error_callback (data, "executable file is unexpected ELF class", 0); - goto fail; - } - - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB - && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) - { - error_callback (data, "executable file has unknown endianness", 0); - goto fail; - } - - /* If the executable is ET_DYN, it is either a PIE, or we are running - directly a shared library with .interp. We need to wait for - dl_iterate_phdr in that case to determine the actual base_address. */ - if (exe && ehdr.e_type == ET_DYN) - return -1; - - shoff = ehdr.e_shoff; - shnum = ehdr.e_shnum; - shstrndx = ehdr.e_shstrndx; - - if ((shnum == 0 || shstrndx == SHN_XINDEX) - && shoff != 0) - { - struct backtrace_view shdr_view; - const b_elf_shdr *shdr; - - if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, - error_callback, data, &shdr_view)) - goto fail; - - shdr = (const b_elf_shdr *) shdr_view.data; - - if (shnum == 0) - shnum = shdr->sh_size; - - if (shstrndx == SHN_XINDEX) - { - shstrndx = shdr->sh_link; - - /* Versions of the GNU binutils between 2.12 and 2.18 did - not handle objects with more than SHN_LORESERVE sections - correctly. All large section indexes were offset by - 0x100. There is more information at - http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . - Fortunately these object files are easy to detect, as the - GNU binutils always put the section header string table - near the end of the list of sections. Thus if the - section header string table index is larger than the - number of sections, then we know we have to subtract - 0x100 to get the real section index. */ - if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) - shstrndx -= 0x100; - } - - backtrace_release_view (state, &shdr_view, error_callback, data); - } - - /* To translate PC to file/line when using DWARF, we need to find - the .debug_info and .debug_line sections. */ - - /* Read the section headers, skipping the first one. */ - - if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), - (shnum - 1) * sizeof (b_elf_shdr), - error_callback, data, &shdrs_view)) - goto fail; - shdrs_view_valid = 1; - shdrs = (const b_elf_shdr *) shdrs_view.data; - - /* Read the section names. */ - - shstrhdr = &shdrs[shstrndx - 1]; - shstr_size = shstrhdr->sh_size; - shstr_off = shstrhdr->sh_offset; - - if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size, - error_callback, data, &names_view)) - goto fail; - names_view_valid = 1; - names = (const char *) names_view.data; - - symtab_shndx = 0; - dynsym_shndx = 0; - - memset (sections, 0, sizeof sections); - - /* Look for the symbol table. */ - for (i = 1; i < shnum; ++i) - { - const b_elf_shdr *shdr; - unsigned int sh_name; - const char *name; - int j; - - shdr = &shdrs[i - 1]; - - if (shdr->sh_type == SHT_SYMTAB) - symtab_shndx = i; - else if (shdr->sh_type == SHT_DYNSYM) - dynsym_shndx = i; - - sh_name = shdr->sh_name; - if (sh_name >= shstr_size) - { - error_callback (data, "ELF section name out of range", 0); - goto fail; - } - - name = names + sh_name; - - for (j = 0; j < (int) DEBUG_MAX; ++j) - { - if (strcmp (name, debug_section_names[j]) == 0) - { - sections[j].offset = shdr->sh_offset; - sections[j].size = shdr->sh_size; - sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0; - break; - } - } - - /* Read the build ID if present. This could check for any - SHT_NOTE section with the right note name and type, but gdb - looks for a specific section name. */ - if (!debuginfo - && !buildid_view_valid - && strcmp (name, ".note.gnu.build-id") == 0) - { - const b_elf_note *note; - - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &buildid_view)) - goto fail; - - buildid_view_valid = 1; - note = (const b_elf_note *) buildid_view.data; - if (note->type == NT_GNU_BUILD_ID - && note->namesz == 4 - && strncmp (note->name, "GNU", 4) == 0 - && shdr->sh_size < 12 + ((note->namesz + 3) & ~ 3) + note->descsz) - { - buildid_data = ¬e->name[0] + ((note->namesz + 3) & ~ 3); - buildid_size = note->descsz; - } - } - - /* Read the debuglink file if present. */ - if (!debuginfo - && !debuglink_view_valid - && strcmp (name, ".gnu_debuglink") == 0) - { - const char *debuglink_data; - size_t crc_offset; - - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &debuglink_view)) - goto fail; - - debuglink_view_valid = 1; - debuglink_data = (const char *) debuglink_view.data; - crc_offset = strnlen (debuglink_data, shdr->sh_size); - crc_offset = (crc_offset + 3) & ~3; - if (crc_offset + 4 <= shdr->sh_size) - { - debuglink_name = debuglink_data; - debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset); - } - } - } - - if (symtab_shndx == 0) - symtab_shndx = dynsym_shndx; - if (symtab_shndx != 0 /* HEAPTRACK: also read symbols from debuginfo file && !debuginfo */) - { - const b_elf_shdr *symtab_shdr; - unsigned int strtab_shndx; - const b_elf_shdr *strtab_shdr; - struct elf_syminfo_data *sdata; - - symtab_shdr = &shdrs[symtab_shndx - 1]; - strtab_shndx = symtab_shdr->sh_link; - if (strtab_shndx >= shnum) - { - error_callback (data, - "ELF symbol table strtab link out of range", 0); - goto fail; - } - strtab_shdr = &shdrs[strtab_shndx - 1]; - - if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, - symtab_shdr->sh_size, error_callback, data, - &symtab_view)) - goto fail; - symtab_view_valid = 1; - - if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, - strtab_shdr->sh_size, error_callback, data, - &strtab_view)) - goto fail; - strtab_view_valid = 1; - - sdata = ((struct elf_syminfo_data *) - backtrace_alloc (state, sizeof *sdata, error_callback, data)); - if (sdata == NULL) - goto fail; - - if (!elf_initialize_syminfo (state, base_address, - symtab_view.data, symtab_shdr->sh_size, - strtab_view.data, strtab_shdr->sh_size, - error_callback, data, sdata)) - { - backtrace_free (state, sdata, sizeof *sdata, error_callback, data); - goto fail; - } - - /* We no longer need the symbol table, but we hold on to the - string table permanently. */ - backtrace_release_view (state, &symtab_view, error_callback, data); - symtab_view_valid = 0; - - *found_sym = 1; - - elf_add_syminfo_data (state, sdata); - } - - backtrace_release_view (state, &shdrs_view, error_callback, data); - shdrs_view_valid = 0; - backtrace_release_view (state, &names_view, error_callback, data); - names_view_valid = 0; - - /* If the debug info is in a separate file, read that one instead. */ - - if (buildid_data != NULL) - { - int d; - - d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size, - error_callback, data); - if (d >= 0) - { - backtrace_release_view (state, &buildid_view, error_callback, data); - if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, - data); - return elf_add (state, NULL, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, 0, 1); - } - } - - if (buildid_view_valid) - { - backtrace_release_view (state, &buildid_view, error_callback, data); - buildid_view_valid = 0; - } - - if (debuglink_name != NULL) - { - int d; - - d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name, - debuglink_crc, error_callback, - data); - if (d >= 0) - { - backtrace_release_view (state, &debuglink_view, error_callback, - data); - return elf_add (state, NULL, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, 0, 1); - } - } - - if (debuglink_view_valid) - { - backtrace_release_view (state, &debuglink_view, error_callback, data); - debuglink_view_valid = 0; - } - - /* Read all the debug sections in a single view, since they are - probably adjacent in the file. We never release this view. */ - - min_offset = 0; - max_offset = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - off_t end; - - if (sections[i].size == 0) - continue; - if (min_offset == 0 || sections[i].offset < min_offset) - min_offset = sections[i].offset; - end = sections[i].offset + sections[i].size; - if (end > max_offset) - max_offset = end; - } - if (min_offset == 0 || max_offset == 0) - { - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - return 1; - } - - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, &debug_view)) - goto fail; - debug_view_valid = 1; - - /* We've read all we need from the executable. */ - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - descriptor = -1; - - using_debug_view = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - if (sections[i].size == 0) - sections[i].data = NULL; - else - { - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - if (i < ZDEBUG_INFO) - ++using_debug_view; - } - } - - /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */ - - zdebug_table = NULL; - for (i = 0; i < ZDEBUG_INFO; ++i) - { - struct debug_section_info *pz; - - pz = §ions[i + ZDEBUG_INFO - DEBUG_INFO]; - if (sections[i].size == 0 && pz->size > 0) - { - unsigned char *uncompressed_data; - size_t uncompressed_size; - - if (zdebug_table == NULL) - { - zdebug_table = ((uint16_t *) - backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - goto fail; - } - - uncompressed_data = NULL; - uncompressed_size = 0; - if (!elf_uncompress_zdebug (state, pz->data, pz->size, zdebug_table, - error_callback, data, - &uncompressed_data, &uncompressed_size)) - goto fail; - sections[i].data = uncompressed_data; - sections[i].size = uncompressed_size; - sections[i].compressed = 0; - } - } - - /* Uncompress the official ELF format - (--compress-debug-sections=zlib-gabi). */ - for (i = 0; i < ZDEBUG_INFO; ++i) - { - unsigned char *uncompressed_data; - size_t uncompressed_size; - - if (sections[i].size == 0 || !sections[i].compressed) - continue; - - if (zdebug_table == NULL) - { - zdebug_table = ((uint16_t *) - backtrace_alloc (state, ZDEBUG_TABLE_SIZE, - error_callback, data)); - if (zdebug_table == NULL) - goto fail; - } - - uncompressed_data = NULL; - uncompressed_size = 0; - if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size, - zdebug_table, error_callback, data, - &uncompressed_data, &uncompressed_size)) - goto fail; - sections[i].data = uncompressed_data; - sections[i].size = uncompressed_size; - sections[i].compressed = 0; - - --using_debug_view; - } - - if (zdebug_table != NULL) - backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE, - error_callback, data); - - if (debug_view_valid && using_debug_view == 0) - { - backtrace_release_view (state, &debug_view, error_callback, data); - debug_view_valid = 0; - } - - if (!backtrace_dwarf_add (state, base_address, - sections[DEBUG_INFO].data, - sections[DEBUG_INFO].size, - sections[DEBUG_LINE].data, - sections[DEBUG_LINE].size, - sections[DEBUG_ABBREV].data, - sections[DEBUG_ABBREV].size, - sections[DEBUG_RANGES].data, - sections[DEBUG_RANGES].size, - sections[DEBUG_STR].data, - sections[DEBUG_STR].size, - ehdr.e_ident[EI_DATA] == ELFDATA2MSB, - error_callback, data, fileline_fn)) - goto fail; - - *found_dwarf = 1; - - return 1; - - fail: - if (shdrs_view_valid) - backtrace_release_view (state, &shdrs_view, error_callback, data); - if (names_view_valid) - backtrace_release_view (state, &names_view, error_callback, data); - if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); - if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); - if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, data); - if (buildid_view_valid) - backtrace_release_view (state, &buildid_view, error_callback, data); - if (debug_view_valid) - backtrace_release_view (state, &debug_view, error_callback, data); - if (descriptor != -1) - backtrace_close (descriptor, error_callback, data); - return 0; -} - -/* Data passed to phdr_callback. */ - -struct phdr_data -{ - struct backtrace_state *state; - backtrace_error_callback error_callback; - void *data; - fileline *fileline_fn; - int *found_sym; - int *found_dwarf; - const char *exe_filename; - int exe_descriptor; -}; - -/* Callback passed to dl_iterate_phdr. Load debug info from shared - libraries. */ - -static int -#ifdef __i386__ -__attribute__ ((__force_align_arg_pointer__)) -#endif -phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, - void *pdata) -{ - struct phdr_data *pd = (struct phdr_data *) pdata; - const char *filename; - int descriptor; - int does_not_exist; - fileline elf_fileline_fn; - int found_dwarf; - - /* There is not much we can do if we don't have the module name, - unless executable is ET_DYN, where we expect the very first - phdr_callback to be for the PIE. */ - if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') - { - if (pd->exe_descriptor == -1) - return 0; - filename = pd->exe_filename; - descriptor = pd->exe_descriptor; - pd->exe_descriptor = -1; - } - else - { - if (pd->exe_descriptor != -1) - { - backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); - pd->exe_descriptor = -1; - } - - filename = info->dlpi_name; - descriptor = backtrace_open (info->dlpi_name, pd->error_callback, - pd->data, &does_not_exist); - if (descriptor < 0) - return 0; - } - - if (elf_add (pd->state, filename, descriptor, info->dlpi_addr, - pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym, - &found_dwarf, 0, 0)) - { - if (found_dwarf) - { - *pd->found_dwarf = 1; - *pd->fileline_fn = elf_fileline_fn; - } - } - - return 0; -} - -/* Initialize the backtrace data we need from an ELF executable. At - the ELF level, all we need to do is find the debug info - sections. */ - -int -backtrace_initialize (struct backtrace_state *state, const char *filename, - int descriptor, backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - int found_sym; - int found_dwarf; - fileline elf_fileline_fn = elf_nodebug; - struct phdr_data pd; - - ret = elf_add (state, filename, descriptor, 0, error_callback, data, - &elf_fileline_fn, &found_sym, &found_dwarf, 1, 0); - if (!ret) - return 0; - - pd.state = state; - pd.error_callback = error_callback; - pd.data = data; - pd.fileline_fn = &elf_fileline_fn; - pd.found_sym = &found_sym; - pd.found_dwarf = &found_dwarf; - pd.exe_filename = filename; - pd.exe_descriptor = ret < 0 ? descriptor : -1; - - dl_iterate_phdr (phdr_callback, (void *) &pd); - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = elf_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = elf_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); - else - (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, - elf_nosyms); - } - - if (!state->threaded) - *fileline_fn = state->fileline_fn; - else - *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - - if (*fileline_fn == NULL || *fileline_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - - return 1; -} diff --git a/3rdparty/libbacktrace/fileline.c b/3rdparty/libbacktrace/fileline.c deleted file mode 100644 index babbe537..00000000 --- a/3rdparty/libbacktrace/fileline.c +++ /dev/null @@ -1,201 +0,0 @@ -/* fileline.c -- Get file and line number information in a backtrace. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef HAVE_GETEXECNAME -#define getexecname() NULL -#endif - -/* Initialize the fileline information from the executable. Returns 1 - on success, 0 on failure. */ - -static int -fileline_initialize (struct backtrace_state *state, - backtrace_error_callback error_callback, void *data) -{ - int failed; - fileline fileline_fn; - int pass; - int called_error_callback; - int descriptor; - const char *filename; - char buf[64]; - - if (!state->threaded) - failed = state->fileline_initialization_failed; - else - failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); - - if (failed) - { - error_callback (data, "failed to read executable information", -1); - return 0; - } - - if (!state->threaded) - fileline_fn = state->fileline_fn; - else - fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (fileline_fn != NULL) - return 1; - - /* We have not initialized the information. Do it now. */ - - descriptor = -1; - called_error_callback = 0; - for (pass = 0; pass < 5; ++pass) - { - int does_not_exist; - - switch (pass) - { - case 0: - filename = state->filename; - break; - case 1: - filename = getexecname (); - break; - case 2: - filename = "/proc/self/exe"; - break; - case 3: - filename = "/proc/curproc/file"; - break; - case 4: - snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", - (long) getpid ()); - filename = buf; - break; - default: - abort (); - } - - if (filename == NULL) - continue; - - descriptor = backtrace_open (filename, error_callback, data, - &does_not_exist); - if (descriptor < 0 && !does_not_exist) - { - called_error_callback = 1; - break; - } - if (descriptor >= 0) - break; - } - - if (descriptor < 0) - { - if (!called_error_callback) - { - if (state->filename != NULL) - error_callback (data, state->filename, ENOENT); - else - error_callback (data, - "libbacktrace could not find executable to open", - 0); - } - failed = 1; - } - - if (!failed) - { - if (!backtrace_initialize (state, filename, descriptor, error_callback, - data, &fileline_fn)) - failed = 1; - } - - if (failed) - { - if (!state->threaded) - state->fileline_initialization_failed = 1; - else - backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); - return 0; - } - - if (!state->threaded) - state->fileline_fn = fileline_fn; - else - { - backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); - - /* Note that if two threads initialize at once, one of the data - sets may be leaked. */ - } - - return 1; -} - -/* Given a PC, find the file name, line number, and function name. */ - -int -backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - return state->fileline_fn (state, pc, callback, error_callback, data); -} - -/* Given a PC, find the symbol for it, and its value. */ - -int -backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - state->syminfo_fn (state, pc, callback, error_callback, data); - return 1; -} diff --git a/3rdparty/libbacktrace/internal.h b/3rdparty/libbacktrace/internal.h deleted file mode 100644 index 2dd6ca32..00000000 --- a/3rdparty/libbacktrace/internal.h +++ /dev/null @@ -1,328 +0,0 @@ -/* internal.h -- Internal header file for stack backtrace library. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_INTERNAL_H -#define BACKTRACE_INTERNAL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* We assume that and "backtrace.h" have already been - included. */ - -#ifndef GCC_VERSION -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -#ifndef ATTRIBUTE_MALLOC -# if (GCC_VERSION >= 2096) -# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) -# else -# define ATTRIBUTE_MALLOC -# endif -#endif - -#ifndef HAVE_SYNC_FUNCTIONS - -/* Define out the sync functions. These should never be called if - they are not available. */ - -#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1) -#define __sync_lock_test_and_set(A, B) (abort(), 0) -#define __sync_lock_release(A) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ - -#ifdef HAVE_ATOMIC_FUNCTIONS - -/* We have the atomic builtin functions. */ - -#define backtrace_atomic_load_pointer(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_load_int(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_store_pointer(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_size_t(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_int(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) - -#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ -#ifdef HAVE_SYNC_FUNCTIONS - -/* We have the sync functions but not the atomic functions. Define - the atomic ones in terms of the sync ones. */ - -extern void *backtrace_atomic_load_pointer (void *); -extern int backtrace_atomic_load_int (int *); -extern void backtrace_atomic_store_pointer (void *, void *); -extern void backtrace_atomic_store_size_t (size_t *, size_t); -extern void backtrace_atomic_store_int (int *, int); - -#else /* !defined (HAVE_SYNC_FUNCTIONS) */ - -/* We have neither the sync nor the atomic functions. These will - never be called. */ - -#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) -#define backtrace_atomic_load_int(p) (abort(), 0) -#define backtrace_atomic_store_pointer(p, v) abort() -#define backtrace_atomic_store_size_t(p, v) abort() -#define backtrace_atomic_store_int(p, v) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ -#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ - -/* The type of the function that collects file/line information. This - is like backtrace_pcinfo. */ - -typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data); - -/* The type of the function that collects symbol information. This is - like backtrace_syminfo. */ - -typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data); - -/* What the backtrace state pointer points to. */ - -struct backtrace_state -{ - /* The name of the executable. */ - const char *filename; - /* Non-zero if threaded. */ - int threaded; - /* The master lock for fileline_fn, fileline_data, syminfo_fn, - syminfo_data, fileline_initialization_failed and everything the - data pointers point to. */ - void *lock; - /* The function that returns file/line information. */ - fileline fileline_fn; - /* The data to pass to FILELINE_FN. */ - void *fileline_data; - /* The function that returns symbol information. */ - syminfo syminfo_fn; - /* The data to pass to SYMINFO_FN. */ - void *syminfo_data; - /* Whether initializing the file/line information failed. */ - int fileline_initialization_failed; - /* The lock for the freelist. */ - int lock_alloc; - /* The freelist when using mmap. */ - struct backtrace_freelist_struct *freelist; -}; - -/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST - is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1 - if the file does not exist. If the file does not exist and - DOES_NOT_EXIST is not NULL, the function will return -1 and will - not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is - NULL, the function will call ERROR_CALLBACK before returning. */ -extern int backtrace_open (const char *filename, - backtrace_error_callback error_callback, - void *data, - int *does_not_exist); - -/* A view of the contents of a file. This supports mmap when - available. A view will remain in memory even after backtrace_close - is called on the file descriptor from which the view was - obtained. */ - -struct backtrace_view -{ - /* The data that the caller requested. */ - const void *data; - /* The base of the view. */ - void *base; - /* The total length of the view. */ - size_t len; -}; - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the - result in *VIEW. Returns 1 on success, 0 on error. */ -extern int backtrace_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view); - -/* Release a view created by backtrace_get_view. */ -extern void backtrace_release_view (struct backtrace_state *state, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data); - -/* Close a file opened by backtrace_open. Returns 1 on success, 0 on - error. */ - -extern int backtrace_close (int descriptor, - backtrace_error_callback error_callback, - void *data); - -/* Sort without using memory. */ - -extern void backtrace_qsort (void *base, size_t count, size_t size, - int (*compar) (const void *, const void *)); - -/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, - this does not report an error, it just returns NULL. */ - -extern void *backtrace_alloc (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data) ATTRIBUTE_MALLOC; - -/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is - NULL, this does not report an error. */ - -extern void backtrace_free (struct backtrace_state *state, void *mem, - size_t size, - backtrace_error_callback error_callback, - void *data); - -/* A growable vector of some struct. This is used for more efficient - allocation when we don't know the final size of some group of data - that we want to represent as an array. */ - -struct backtrace_vector -{ - /* The base of the vector. */ - void *base; - /* The number of bytes in the vector. */ - size_t size; - /* The number of bytes available at the current allocation. */ - size_t alc; -}; - -/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated - bytes. Note that this may move the entire vector to a new memory - location. Returns NULL on failure. */ - -extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data, - struct backtrace_vector *vec); - -/* Finish the current allocation on VEC. Prepare to start a new - allocation. The finished allocation will never be freed. Returns - a pointer to the base of the finished entries, or NULL on - failure. */ - -extern void* backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Release any extra space allocated for VEC. This may change - VEC->base. Returns 1 on success, 0 on failure. */ - -extern int backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Read initial debug data from a descriptor, and set the - fileline_data, syminfo_fn, and syminfo_data fields of STATE. - Return the fileln_fn field in *FILELN_FN--this is done this way so - that the synchronization code is only implemented once. This is - called after the descriptor has first been opened. It will close - the descriptor if it is no longer needed. Returns 1 on success, 0 - on error. There will be multiple implementations of this function, - for different file formats. Each system will compile the - appropriate one. */ - -extern int backtrace_initialize (struct backtrace_state *state, - const char *filename, - int descriptor, - backtrace_error_callback error_callback, - void *data, - fileline *fileline_fn); - -/* Add file/line information for a DWARF module. */ - -extern int backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char* dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_range_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn); - -/* A test-only hook for elf_uncompress_zdebug. */ - -extern int backtrace_uncompress_zdebug (struct backtrace_state *, - const unsigned char *compressed, - size_t compressed_size, - backtrace_error_callback, void *data, - unsigned char **uncompressed, - size_t *uncompressed_size); - -//BEGIN HEAPTRACK -// the following internal functions are used by heaptrack, and thus must be made exported here -extern int elf_add (struct backtrace_state *state, const char *filename, int descriptor, - uintptr_t base_address, backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, - int exe, int debuginfo); -extern void elf_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data); -extern void elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data); -//END HEAPTRACK - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/3rdparty/libbacktrace/mmap.c b/3rdparty/libbacktrace/mmap.c deleted file mode 100644 index cfa50e27..00000000 --- a/3rdparty/libbacktrace/mmap.c +++ /dev/null @@ -1,303 +0,0 @@ -/* mmap.c -- Memory allocation with mmap. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Memory allocation on systems that provide anonymous mmap. This - permits the backtrace functions to be invoked from a signal - handler, assuming that mmap is async-signal safe. */ - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* A list of free memory blocks. */ - -struct backtrace_freelist_struct -{ - /* Next on list. */ - struct backtrace_freelist_struct *next; - /* Size of this block, including this structure. */ - size_t size; -}; - -/* Free memory allocated by backtrace_alloc. */ - -static void -backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) -{ - /* Just leak small blocks. We don't have to be perfect. */ - if (size >= sizeof (struct backtrace_freelist_struct)) - { - struct backtrace_freelist_struct *p; - - p = (struct backtrace_freelist_struct *) addr; - p->next = state->freelist; - p->size = size; - state->freelist = p; - } -} - -/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't - report an error. */ - -void * -backtrace_alloc (struct backtrace_state *state, - size_t size, backtrace_error_callback error_callback, - void *data) -{ - void *ret; - int locked; - struct backtrace_freelist_struct **pp; - size_t pagesize; - size_t asksize; - void *page; - - ret = NULL; - - /* If we can acquire the lock, then see if there is space on the - free list. If we can't acquire the lock, drop straight into - using mmap. __sync_lock_test_and_set returns the old state of - the lock, so we have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->size >= size) - { - struct backtrace_freelist_struct *p; - - p = *pp; - *pp = p->next; - - /* Round for alignment; we assume that no type we care about - is more than 8 bytes. */ - size = (size + 7) & ~ (size_t) 7; - if (size < p->size) - backtrace_free_locked (state, (char *) p + size, - p->size - size); - - ret = (void *) p; - - break; - } - } - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } - - if (ret == NULL) - { - /* Allocate a new page. */ - - pagesize = getpagesize (); - asksize = (size + pagesize - 1) & ~ (pagesize - 1); - page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (page == MAP_FAILED) - { - if (error_callback) - error_callback (data, "mmap", errno); - } - else - { - size = (size + 7) & ~ (size_t) 7; - if (size < asksize) - backtrace_free (state, (char *) page + size, asksize - size, - error_callback, data); - - ret = page; - } - } - - return ret; -} - -/* Free memory allocated by backtrace_alloc. */ - -void -backtrace_free (struct backtrace_state *state, void *addr, size_t size, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - int locked; - - /* If we are freeing a large aligned block, just release it back to - the system. This case arises when growing a vector for a large - binary with lots of debug info. Calling munmap here may cause us - to call mmap again if there is also a large shared library; we - just live with that. */ - if (size >= 16 * 4096) - { - size_t pagesize; - - pagesize = getpagesize (); - if (((uintptr_t) addr & (pagesize - 1)) == 0 - && (size & (pagesize - 1)) == 0) - { - /* If munmap fails for some reason, just add the block to - the freelist. */ - if (munmap (addr, size) == 0) - return; - } - } - - /* If we can acquire the lock, add the new space to the free list. - If we can't acquire the lock, just leak the memory. - __sync_lock_test_and_set returns the old state of the lock, so we - have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - backtrace_free_locked (state, addr, size); - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } -} - -/* Grow VEC by SIZE bytes. */ - -void * -backtrace_vector_grow (struct backtrace_state *state,size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_vector *vec) -{ - void *ret; - - if (size > vec->alc) - { - size_t pagesize; - size_t alc; - void *base; - - pagesize = getpagesize (); - alc = vec->size + size; - if (vec->size == 0) - alc = 16 * size; - else if (alc < pagesize) - { - alc *= 2; - if (alc > pagesize) - alc = pagesize; - } - else - { - alc *= 2; - alc = (alc + pagesize - 1) & ~ (pagesize - 1); - } - base = backtrace_alloc (state, alc, error_callback, data); - if (base == NULL) - return NULL; - if (vec->base != NULL) - { - memcpy (base, vec->base, vec->size); - backtrace_free (state, vec->base, vec->size + vec->alc, - error_callback, data); - } - vec->base = base; - vec->alc = alc - vec->size; - } - - ret = (char *) vec->base + vec->size; - vec->size += size; - vec->alc -= size; - return ret; -} - -/* Finish the current allocation on VEC. */ - -void * -backtrace_vector_finish ( - struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - void *ret; - - ret = vec->base; - vec->base = (char *) vec->base + vec->size; - vec->size = 0; - return ret; -} - -/* Release any extra space allocated for VEC. */ - -int -backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - size_t size; - size_t alc; - size_t aligned; - - /* Make sure that the block that we free is aligned on an 8-byte - boundary. */ - size = vec->size; - alc = vec->alc; - aligned = (size + 7) & ~ (size_t) 7; - alc -= aligned - size; - - backtrace_free (state, (char *) vec->base + aligned, alc, - error_callback, data); - vec->alc = 0; - return 1; -} diff --git a/3rdparty/libbacktrace/mmapio.c b/3rdparty/libbacktrace/mmapio.c deleted file mode 100644 index 129785d3..00000000 --- a/3rdparty/libbacktrace/mmapio.c +++ /dev/null @@ -1,100 +0,0 @@ -/* mmapio.c -- File views using mmap. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* This file implements file views and memory allocation when mmap is - available. */ - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ - -int -backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor, off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view) -{ - size_t pagesize; - unsigned int inpage; - off_t pageoff; - void *map; - - pagesize = getpagesize (); - inpage = offset % pagesize; - pageoff = offset - inpage; - - size += inpage; - size = (size + (pagesize - 1)) & ~ (pagesize - 1); - - map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff); - if (map == MAP_FAILED) - { - error_callback (data, "mmap", errno); - return 0; - } - - view->data = (char *) map + inpage; - view->base = map; - view->len = size; - - return 1; -} - -/* Release a view read by backtrace_get_view. */ - -void -backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data) -{ - union { - const void *cv; - void *v; - } const_cast; - - const_cast.cv = view->base; - if (munmap (const_cast.v, view->len) < 0) - error_callback (data, "munmap", errno); -} diff --git a/3rdparty/libbacktrace/nounwind.c b/3rdparty/libbacktrace/nounwind.c deleted file mode 100644 index 8dc6bf62..00000000 --- a/3rdparty/libbacktrace/nounwind.c +++ /dev/null @@ -1,66 +0,0 @@ -/* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" - -#include "internal.h" - -/* This source file is compiled if the unwind library is not - available. */ - -int -backtrace_full (struct backtrace_state *state ATTRIBUTE_UNUSED, - int skip ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, - "no stack trace because unwind library not available", - 0); - return 0; -} - -int -backtrace_simple (struct backtrace_state *state ATTRIBUTE_UNUSED, - int skip ATTRIBUTE_UNUSED, - backtrace_simple_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, - "no stack trace because unwind library not available", - 0); - return 0; -} diff --git a/3rdparty/libbacktrace/posix.c b/3rdparty/libbacktrace/posix.c deleted file mode 100644 index 5e5571f7..00000000 --- a/3rdparty/libbacktrace/posix.c +++ /dev/null @@ -1,100 +0,0 @@ -/* posix.c -- POSIX file I/O routines for the backtrace library. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - -/* Open a file for reading. */ - -int -backtrace_open (const char *filename, backtrace_error_callback error_callback, - void *data, int *does_not_exist) -{ - int descriptor; - - if (does_not_exist != NULL) - *does_not_exist = 0; - - descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); - if (descriptor < 0) - { - if (does_not_exist != NULL && errno == ENOENT) - *does_not_exist = 1; - else - error_callback (data, filename, errno); - return -1; - } - -#ifdef HAVE_FCNTL - /* Set FD_CLOEXEC just in case the kernel does not support - O_CLOEXEC. It doesn't matter if this fails for some reason. - FIXME: At some point it should be safe to only do this if - O_CLOEXEC == 0. */ - fcntl (descriptor, F_SETFD, FD_CLOEXEC); -#endif - - return descriptor; -} - -/* Close DESCRIPTOR. */ - -int -backtrace_close (int descriptor, backtrace_error_callback error_callback, - void *data) -{ - if (close (descriptor) < 0) - { - error_callback (data, "close", errno); - return 0; - } - return 1; -} diff --git a/3rdparty/libbacktrace/print.c b/3rdparty/libbacktrace/print.c deleted file mode 100644 index d19fc17b..00000000 --- a/3rdparty/libbacktrace/print.c +++ /dev/null @@ -1,92 +0,0 @@ -/* print.c -- Print the current backtrace. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Passed to callbacks. */ - -struct print_data -{ - struct backtrace_state *state; - FILE *f; -}; - -/* Print one level of a backtrace. */ - -static int -print_callback (void *data, uintptr_t pc, const char *filename, int lineno, - const char *function) -{ - struct print_data *pdata = (struct print_data *) data; - - fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", - (unsigned long) pc, - function == NULL ? "???" : function, - filename == NULL ? "???" : filename, - lineno); - return 0; -} - -/* Print errors to stderr. */ - -static void -error_callback (void *data, const char *msg, int errnum) -{ - struct print_data *pdata = (struct print_data *) data; - - if (pdata->state->filename != NULL) - fprintf (stderr, "%s: ", pdata->state->filename); - fprintf (stderr, "libbacktrace: %s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fputc ('\n', stderr); -} - -/* Print a backtrace. */ - -void -backtrace_print (struct backtrace_state *state, int skip, FILE *f) -{ - struct print_data data; - - data.state = state; - data.f = f; - backtrace_full (state, skip + 1, print_callback, error_callback, - (void *) &data); -} diff --git a/3rdparty/libbacktrace/read.c b/3rdparty/libbacktrace/read.c deleted file mode 100644 index ed740336..00000000 --- a/3rdparty/libbacktrace/read.c +++ /dev/null @@ -1,96 +0,0 @@ -/* read.c -- File views without mmap. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* This file implements file views when mmap is not available. */ - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ - -int -backtrace_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view) -{ - ssize_t got; - - if (lseek (descriptor, offset, SEEK_SET) < 0) - { - error_callback (data, "lseek", errno); - return 0; - } - - view->base = backtrace_alloc (state, size, error_callback, data); - if (view->base == NULL) - return 0; - view->data = view->base; - view->len = size; - - got = read (descriptor, view->base, size); - if (got < 0) - { - error_callback (data, "read", errno); - free (view->base); - return 0; - } - - if ((size_t) got < size) - { - error_callback (data, "file too short", 0); - free (view->base); - return 0; - } - - return 1; -} - -/* Release a view read by backtrace_get_view. */ - -void -backtrace_release_view (struct backtrace_state *state, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data) -{ - backtrace_free (state, view->base, view->len, error_callback, data); - view->data = NULL; - view->base = NULL; -} diff --git a/3rdparty/libbacktrace/simple.c b/3rdparty/libbacktrace/simple.c deleted file mode 100644 index 6d65e608..00000000 --- a/3rdparty/libbacktrace/simple.c +++ /dev/null @@ -1,108 +0,0 @@ -/* simple.c -- The backtrace_simple function. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include "unwind.h" -#include "backtrace.h" - -/* The simple_backtrace routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_simple_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_simple_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routine. */ - void *data; - /* Value to return from backtrace. */ - int ret; -}; - -/* Unwind library callback routine. This is passd to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -simple_unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - bdata->ret = bdata->callback (bdata->data, pc); - - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a simple stack backtrace. */ - -int -backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_simple_data bdata; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - _Unwind_Backtrace (simple_unwind, &bdata); - return bdata.ret; -} diff --git a/3rdparty/libbacktrace/sort.c b/3rdparty/libbacktrace/sort.c deleted file mode 100644 index 6f34e0ac..00000000 --- a/3rdparty/libbacktrace/sort.c +++ /dev/null @@ -1,108 +0,0 @@ -/* sort.c -- Sort without allocating memory - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* The GNU glibc version of qsort allocates memory, which we must not - do if we are invoked by a signal handler. So provide our own - sort. */ - -static void -swap (char *a, char *b, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++, a++, b++) - { - char t; - - t = *a; - *a = *b; - *b = t; - } -} - -void -backtrace_qsort (void *basearg, size_t count, size_t size, - int (*compar) (const void *, const void *)) -{ - char *base = (char *) basearg; - size_t i; - size_t mid; - - tail_recurse: - if (count < 2) - return; - - /* The symbol table and DWARF tables, which is all we use this - routine for, tend to be roughly sorted. Pick the middle element - in the array as our pivot point, so that we are more likely to - cut the array in half for each recursion step. */ - swap (base, base + (count / 2) * size, size); - - mid = 0; - for (i = 1; i < count; i++) - { - if ((*compar) (base, base + i * size) > 0) - { - ++mid; - if (i != mid) - swap (base + mid * size, base + i * size, size); - } - } - - if (mid > 0) - swap (base, base + mid * size, size); - - /* Recurse with the smaller array, loop with the larger one. That - ensures that our maximum stack depth is log count. */ - if (2 * mid < count) - { - backtrace_qsort (base, mid, size, compar); - base += (mid + 1) * size; - count -= mid + 1; - goto tail_recurse; - } - else - { - backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), - size, compar); - count = mid; - goto tail_recurse; - } -} diff --git a/3rdparty/libbacktrace/state.c b/3rdparty/libbacktrace/state.c deleted file mode 100644 index b50ec029..00000000 --- a/3rdparty/libbacktrace/state.c +++ /dev/null @@ -1,72 +0,0 @@ -/* state.c -- Create the backtrace state. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* Create the backtrace state. This will then be passed to all the - other routines. */ - -struct backtrace_state * -backtrace_create_state (const char *filename, int threaded, - backtrace_error_callback error_callback, - void *data) -{ - struct backtrace_state init_state; - struct backtrace_state *state; - -#ifndef HAVE_SYNC_FUNCTIONS - if (threaded) - { - error_callback (data, "backtrace library does not support threads", 0); - return NULL; - } -#endif - - memset (&init_state, 0, sizeof init_state); - init_state.filename = filename; - init_state.threaded = threaded; - - state = ((struct backtrace_state *) - backtrace_alloc (&init_state, sizeof *state, error_callback, data)); - if (state == NULL) - return NULL; - *state = init_state; - - return state; -} diff --git a/3rdparty/libbacktrace/unknown.c b/3rdparty/libbacktrace/unknown.c deleted file mode 100644 index 5df6d15f..00000000 --- a/3rdparty/libbacktrace/unknown.c +++ /dev/null @@ -1,65 +0,0 @@ -/* unknown.c -- used when backtrace configury does not know file format. - Copyright (C) 2012-2017 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" -#include "internal.h" - -/* A trivial routine that always fails to find fileline data. */ - -static int -unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc, backtrace_full_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) - -{ - return callback (data, pc, NULL, 0, NULL); -} - -/* Initialize the backtrace data when we don't know how to read the - debug info. */ - -int -backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED, - const char *filename ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, fileline *fileline_fn) -{ - state->fileline_data = NULL; - *fileline_fn = unknown_fileline; - return 1; -} diff --git a/3rdparty/robin-map/.codecov.yml b/3rdparty/robin-map/.codecov.yml new file mode 100644 index 00000000..92a0a4a0 --- /dev/null +++ b/3rdparty/robin-map/.codecov.yml @@ -0,0 +1,5 @@ +comment: off +coverage: + status: + project: off + patch: off diff --git a/3rdparty/robin-map/CMakeLists.txt b/3rdparty/robin-map/CMakeLists.txt new file mode 100644 index 00000000..30ae333e --- /dev/null +++ b/3rdparty/robin-map/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.1) + +project(tsl-robin-map VERSION 1.2.1 LANGUAGES CXX) + +include(GNUInstallDirs) + + +add_library(robin_map INTERFACE) +# Use tsl::robin_map as target, more consistent with other libraries conventions (Boost, Qt, ...) +add_library(tsl::robin_map ALIAS robin_map) + +target_include_directories(robin_map INTERFACE + "$" + "$") + +list(APPEND headers "${CMAKE_CURRENT_SOURCE_DIR}/include/tsl/robin_growth_policy.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/tsl/robin_hash.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/tsl/robin_map.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/tsl/robin_set.h") +target_sources(robin_map INTERFACE "$") + +if(MSVC) + target_sources(robin_map INTERFACE + "$" + "$") +endif() + + + + +set(IS_SUBPROJECT TRUE) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + set(IS_SUBPROJECT FALSE) +endif() + +# Installation (only compatible with CMake version >= 3.3) +if(NOT IS_SUBPROJECT AND ${CMAKE_VERSION} VERSION_GREATER "3.2") + include(CMakePackageConfigHelpers) + + ## Install include directory and potential natvis file + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/tsl" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + + if(MSVC) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/tsl-robin-map.natvis" + DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}") + endif() + + + + ## Create and install tsl-robin-mapConfig.cmake + configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/tsl-robin-mapConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/tsl-robin-mapConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/tsl-robin-map") + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tsl-robin-mapConfig.cmake" + DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/tsl-robin-map") + + + ## Create local tsl-robin-mapTargets.cmake + export(TARGETS robin_map NAMESPACE tsl:: FILE "${CMAKE_CURRENT_BINARY_DIR}/tsl-robin-mapTargets.cmake") + + ## Create and install global tsl-robin-mapTargets.cmake + install(TARGETS robin_map + EXPORT tsl-robin-mapTargets) + + install(EXPORT tsl-robin-mapTargets + NAMESPACE tsl:: + DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/tsl-robin-map") + + + + ## Create and install tsl-robin-mapConfigVersion.cmake + # tsl-robin-map is header-only and does not depend on the architecture. + # Remove CMAKE_SIZEOF_VOID_P from tsl-robin-mapConfigVersion.cmake so that a + # tsl-robin-mapConfig.cmake generated for a 64 bit target can be used for 32 bit + # targets and vice versa. + set(CMAKE_SIZEOF_VOID_P_BACKUP ${CMAKE_SIZEOF_VOID_P}) + unset(CMAKE_SIZEOF_VOID_P) + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/tsl-robin-mapConfigVersion.cmake" + COMPATIBILITY SameMajorVersion) + set(CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P_BACKUP}) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tsl-robin-mapConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/tsl-robin-map") +endif() diff --git a/3rdparty/libbacktrace/LICENSE.vogl b/3rdparty/robin-map/LICENSE similarity index 81% rename from 3rdparty/libbacktrace/LICENSE.vogl rename to 3rdparty/robin-map/LICENSE index 89535614..e9c5ae95 100644 --- a/3rdparty/libbacktrace/LICENSE.vogl +++ b/3rdparty/robin-map/LICENSE @@ -1,8 +1,6 @@ -applies to: btrace.h, btrace.cpp, CMakeLists.txt +MIT License -Copyright 2013-2014 RAD Game Tools and Valve Software - -All Rights Reserved. +Copyright (c) 2017 Thibaut Goetghebuer-Planchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -11,14 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/3rdparty/robin-map/README.md b/3rdparty/robin-map/README.md new file mode 100644 index 00000000..f8901e45 --- /dev/null +++ b/3rdparty/robin-map/README.md @@ -0,0 +1,483 @@ +[![CI](https://github.com/Tessil/robin-map/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Tessil/robin-map/actions/workflows/ci.yml) + +## A C++ implementation of a fast hash map and hash set using robin hood hashing + +The robin-map library is a C++ implementation of a fast hash map and hash set using open-addressing and linear robin hood hashing with backward shift deletion to resolve collisions. + +Four classes are provided: `tsl::robin_map`, `tsl::robin_set`, `tsl::robin_pg_map` and `tsl::robin_pg_set`. The first two are faster and use a power of two growth policy, the last two use a prime growth policy instead and are able to cope better with a poor hash function. Use the prime version if there is a chance of repeating patterns in the lower bits of your hash (e.g. you are storing pointers with an identity hash function). See [GrowthPolicy](#growth-policy) for details. + +A **benchmark** of `tsl::robin_map` against other hash maps may be found [here](https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html). This page also gives some advices on which hash table structure you should try for your use case (useful if you are a bit lost with the multiple hash tables implementations in the `tsl` namespace). + +### Key features + +- Header-only library, just add the [include](include/) directory to your include path and you are ready to go. If you use CMake, you can also use the `tsl::robin_map` exported target from the [CMakeLists.txt](CMakeLists.txt). +- Fast hash table, check the [benchmark](https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html) for some numbers. +- Support for move-only and non-default constructible key/value. +- Support for heterogeneous lookups allowing the usage of `find` with a type different than `Key` (e.g. if you have a map that uses `std::unique_ptr` as key, you can use a `foo*` or a `std::uintptr_t` as key parameter to `find` without constructing a `std::unique_ptr`, see [example](#heterogeneous-lookups)). +- No need to reserve any sentinel value from the keys. +- Possibility to store the hash value alongside the stored key-value for faster rehash and lookup if the hash or the key equal functions are expensive to compute. Note that hash may be stored even if not asked explicitly when the library can detect that it will have no impact on the size of the structure in memory due to alignment. See the [StoreHash](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html#details) template parameter for details. +- If the hash is known before a lookup, it is possible to pass it as parameter to speed-up the lookup (see `precalculated_hash` parameter in [API](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html#a35021b11aabb61820236692a54b3a0f8)). +- Support for efficient serialization and deserialization (see [example](#serialization) and the `serialize/deserialize` methods in the [API](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html) for details). +- The library can be used with exceptions disabled (through `-fno-exceptions` option on Clang and GCC, without an `/EH` option on MSVC or simply by defining `TSL_NO_EXCEPTIONS`). `std::terminate` is used in replacement of the `throw` instruction when exceptions are disabled. +- API closely similar to `std::unordered_map` and `std::unordered_set`. + +### Differences compared to `std::unordered_map` + +`tsl::robin_map` tries to have an interface similar to `std::unordered_map`, but some differences exist. +- The **strong exception guarantee only holds** if the following statement is true `std::is_nothrow_swappable::value && std::is_nothrow_move_constructible::value` (where `value_type` is `Key` for `tsl::robin_set` and `std::pair` for `tsl::robin_map`). Otherwise if an exception is thrown during the swap or the move, the structure may end up in a undefined state. Note that per the standard, a `value_type` with a noexcept copy constructor and no move constructor also satisfies this condition and will thus guarantee the strong exception guarantee for the structure (see [API](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html#details) for details). +- The type `Key`, and also `T` in case of map, must be swappable. They must also be copy and/or move constructible. +- Iterator invalidation doesn't behave in the same way, any operation modifying the hash table invalidate them (see [API](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html#details) for details). +- References and pointers to keys or values in the map are invalidated in the same way as iterators to these keys-values. +- For iterators of `tsl::robin_map`, `operator*()` and `operator->()` return a reference and a pointer to `const std::pair` instead of `std::pair` making the value `T` not modifiable. To modify the value you have to call the `value()` method of the iterator to get a mutable reference. Example: +```c++ +tsl::robin_map map = {{1, 1}, {2, 1}, {3, 1}}; +for(auto it = map.begin(); it != map.end(); ++it) { + //it->second = 2; // Illegal + it.value() = 2; // Ok +} +``` +- No support for some buckets related methods (like `bucket_size`, `bucket`, ...). + +These differences also apply between `std::unordered_set` and `tsl::robin_set`. + +Thread-safety guarantees are the same as `std::unordered_map/set` (i.e. possible to have multiple readers with no writer). + +### Growth policy + +The library supports multiple growth policies through the `GrowthPolicy` template parameter. Three policies are provided by the library but you can easily implement your own if needed. + +* **[tsl::rh::power_of_two_growth_policy.](https://tessil.github.io/robin-map/classtsl_1_1rh_1_1power__of__two__growth__policy.html)** Default policy used by `tsl::robin_map/set`. This policy keeps the size of the bucket array of the hash table to a power of two. This constraint allows the policy to avoid the usage of the slow modulo operation to map a hash to a bucket, instead of hash % 2n, it uses hash & (2n - 1) (see [fast modulo](https://en.wikipedia.org/wiki/Modulo_operation#Performance_issues)). Fast but this may cause a lot of collisions with a poor hash function as the modulo with a power of two only masks the most significant bits in the end. +* **[tsl::rh::prime_growth_policy.](https://tessil.github.io/robin-map/classtsl_1_1rh_1_1prime__growth__policy.html)** Default policy used by `tsl::robin_pg_map/set`. The policy keeps the size of the bucket array of the hash table to a prime number. When mapping a hash to a bucket, using a prime number as modulo will result in a better distribution of the hash across the buckets even with a poor hash function. To allow the compiler to optimize the modulo operation, the policy use a lookup table with constant primes modulos (see [API](https://tessil.github.io/robin-map/classtsl_1_1rh_1_1prime__growth__policy.html#details) for details). Slower than `tsl::rh::power_of_two_growth_policy` but more secure. +* **[tsl::rh::mod_growth_policy.](https://tessil.github.io/robin-map/classtsl_1_1rh_1_1mod__growth__policy.html)** The policy grows the map by a customizable growth factor passed in parameter. It then just use the modulo operator to map a hash to a bucket. Slower but more flexible. + + +To implement your own policy, you have to implement the following interface. + +```c++ +struct custom_policy { + // Called on hash table construction and rehash, min_bucket_count_in_out is the minimum buckets + // that the hash table needs. The policy can change it to a higher number of buckets if needed + // and the hash table will use this value as bucket count. If 0 bucket is asked, then the value + // must stay at 0. + explicit custom_policy(std::size_t& min_bucket_count_in_out); + + // Return the bucket [0, bucket_count()) to which the hash belongs. + // If bucket_count() is 0, it must always return 0. + std::size_t bucket_for_hash(std::size_t hash) const noexcept; + + // Return the number of buckets that should be used on next growth + std::size_t next_bucket_count() const; + + // Maximum number of buckets supported by the policy + std::size_t max_bucket_count() const; + + // Reset the growth policy as if the policy was created with a bucket count of 0. + // After a clear, the policy must always return 0 when bucket_for_hash() is called. + void clear() noexcept; +} +``` + +### Installation + +To use robin-map, just add the [include](include/) directory to your include path. It is a **header-only** library. + +If you use CMake, you can also use the `tsl::robin_map` exported target from the [CMakeLists.txt](CMakeLists.txt) with `target_link_libraries`. +```cmake +# Example where the robin-map project is stored in a third-party directory +add_subdirectory(third-party/robin-map) +target_link_libraries(your_target PRIVATE tsl::robin_map) +``` + +If the project has been installed through `make install`, you can also use `find_package(tsl-robin-map REQUIRED)` instead of `add_subdirectory`. + +The library is available in [vcpkg](https://github.com/Microsoft/vcpkg/tree/master/ports/robin-map) and [conan](https://conan.io/center/tsl-robin-map). It's also present in [Debian](https://packages.debian.org/buster/robin-map-dev), [Ubuntu](https://packages.ubuntu.com/disco/robin-map-dev) and [Fedora](https://apps.fedoraproject.org/packages/robin-map-devel) package repositories. + +The code should work with any C++11 standard-compliant compiler and has been tested with GCC 4.8.4, Clang 3.5.0 and Visual Studio 2015. + +To run the tests you will need the Boost Test library and CMake. + +```bash +git clone https://github.com/Tessil/robin-map.git +cd robin-map/tests +mkdir build +cd build +cmake .. +cmake --build . +./tsl_robin_map_tests +``` + +### Usage + +The API can be found [here](https://tessil.github.io/robin-map/). + +All methods are not documented yet, but they replicate the behavior of the ones in `std::unordered_map` and `std::unordered_set`, except if specified otherwise. + + +### Example + +```c++ +#include +#include +#include +#include +#include + +int main() { + tsl::robin_map map = {{"a", 1}, {"b", 2}}; + map["c"] = 3; + map["d"] = 4; + + map.insert({"e", 5}); + map.erase("b"); + + for(auto it = map.begin(); it != map.end(); ++it) { + //it->second += 2; // Not valid. + it.value() += 2; + } + + // {d, 6} {a, 3} {e, 7} {c, 5} + for(const auto& key_value : map) { + std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl; + } + + + if(map.find("a") != map.end()) { + std::cout << "Found \"a\"." << std::endl; + } + + const std::size_t precalculated_hash = std::hash()("a"); + // If we already know the hash beforehand, we can pass it in parameter to speed-up lookups. + if(map.find("a", precalculated_hash) != map.end()) { + std::cout << "Found \"a\" with hash " << precalculated_hash << "." << std::endl; + } + + + /* + * Calculating the hash and comparing two std::string may be slow. + * We can store the hash of each std::string in the hash map to make + * the inserts and lookups faster by setting StoreHash to true. + */ + tsl::robin_map, + std::equal_to, + std::allocator>, + true> map2; + + map2["a"] = 1; + map2["b"] = 2; + + // {a, 1} {b, 2} + for(const auto& key_value : map2) { + std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl; + } + + + + + tsl::robin_set set; + set.insert({1, 9, 0}); + set.insert({2, -1, 9}); + + // {0} {1} {2} {9} {-1} + for(const auto& key : set) { + std::cout << "{" << key << "}" << std::endl; + } +} +``` + +#### Heterogeneous lookups + +Heterogeneous overloads allow the usage of other types than `Key` for lookup and erase operations as long as the used types are hashable and comparable to `Key`. + +To activate the heterogeneous overloads in `tsl::robin_map/set`, the qualified-id `KeyEqual::is_transparent` must be valid. It works the same way as for [`std::map::find`](http://en.cppreference.com/w/cpp/container/map/find). You can either use [`std::equal_to<>`](http://en.cppreference.com/w/cpp/utility/functional/equal_to_void) or define your own function object. + +Both `KeyEqual` and `Hash` will need to be able to deal with the different types. + +```c++ +#include +#include +#include +#include + + +struct employee { + employee(int id, std::string name) : m_id(id), m_name(std::move(name)) { + } + + // Either we include the comparators in the class and we use `std::equal_to<>`... + friend bool operator==(const employee& empl, int empl_id) { + return empl.m_id == empl_id; + } + + friend bool operator==(int empl_id, const employee& empl) { + return empl_id == empl.m_id; + } + + friend bool operator==(const employee& empl1, const employee& empl2) { + return empl1.m_id == empl2.m_id; + } + + + int m_id; + std::string m_name; +}; + +// ... or we implement a separate class to compare employees. +struct equal_employee { + using is_transparent = void; + + bool operator()(const employee& empl, int empl_id) const { + return empl.m_id == empl_id; + } + + bool operator()(int empl_id, const employee& empl) const { + return empl_id == empl.m_id; + } + + bool operator()(const employee& empl1, const employee& empl2) const { + return empl1.m_id == empl2.m_id; + } +}; + +struct hash_employee { + std::size_t operator()(const employee& empl) const { + return std::hash()(empl.m_id); + } + + std::size_t operator()(int id) const { + return std::hash()(id); + } +}; + + +int main() { + // Use std::equal_to<> which will automatically deduce and forward the parameters + tsl::robin_map> map; + map.insert({employee(1, "John Doe"), 2001}); + map.insert({employee(2, "Jane Doe"), 2002}); + map.insert({employee(3, "John Smith"), 2003}); + + // John Smith 2003 + auto it = map.find(3); + if(it != map.end()) { + std::cout << it->first.m_name << " " << it->second << std::endl; + } + + map.erase(1); + + + + // Use a custom KeyEqual which has an is_transparent member type + tsl::robin_map map2; + map2.insert({employee(4, "Johnny Doe"), 2004}); + + // 2004 + std::cout << map2.at(4) << std::endl; +} +``` + + +#### Serialization + +The library provides an efficient way to serialize and deserialize a map or a set so that it can be saved to a file or send through the network. +To do so, it requires the user to provide a function object for both serialization and deserialization. + +```c++ +struct serializer { + // Must support the following types for U: std::int16_t, std::uint32_t, + // std::uint64_t, float and std::pair if a map is used or Key for + // a set. + template + void operator()(const U& value); +}; +``` + +```c++ +struct deserializer { + // Must support the following types for U: std::int16_t, std::uint32_t, + // std::uint64_t, float and std::pair if a map is used or Key for + // a set. + template + U operator()(); +}; +``` + +Note that the implementation leaves binary compatibility (endianness, float binary representation, size of int, ...) of the types it serializes/deserializes in the hands of the provided function objects if compatibility is required. + +More details regarding the `serialize` and `deserialize` methods can be found in the [API](https://tessil.github.io/robin-map/classtsl_1_1robin__map.html). + +```c++ +#include +#include +#include +#include +#include + + +class serializer { +public: + serializer(const char* file_name) { + m_ostream.exceptions(m_ostream.badbit | m_ostream.failbit); + m_ostream.open(file_name, std::ios::binary); + } + + template::value>::type* = nullptr> + void operator()(const T& value) { + m_ostream.write(reinterpret_cast(&value), sizeof(T)); + } + + void operator()(const std::pair& value) { + (*this)(value.first); + (*this)(value.second); + } + +private: + std::ofstream m_ostream; +}; + +class deserializer { +public: + deserializer(const char* file_name) { + m_istream.exceptions(m_istream.badbit | m_istream.failbit | m_istream.eofbit); + m_istream.open(file_name, std::ios::binary); + } + + template + T operator()() { + T value; + deserialize(value); + + return value; + } + +private: + template::value>::type* = nullptr> + void deserialize(T& value) { + m_istream.read(reinterpret_cast(&value), sizeof(T)); + } + + void deserialize(std::pair& value) { + deserialize(value.first); + deserialize(value.second); + } + +private: + std::ifstream m_istream; +}; + + +int main() { + const tsl::robin_map map = {{1, -1}, {2, -2}, {3, -3}, {4, -4}}; + + + const char* file_name = "robin_map.data"; + { + serializer serial(file_name); + map.serialize(serial); + } + + { + deserializer dserial(file_name); + auto map_deserialized = tsl::robin_map::deserialize(dserial); + + assert(map == map_deserialized); + } + + { + deserializer dserial(file_name); + + /** + * If the serialized and deserialized map are hash compatibles (see conditions in API), + * setting the argument to true speed-up the deserialization process as we don't have + * to recalculate the hash of each key. We also know how much space each bucket needs. + */ + const bool hash_compatible = true; + auto map_deserialized = + tsl::robin_map::deserialize(dserial, hash_compatible); + + assert(map == map_deserialized); + } +} +``` + +##### Serialization with Boost Serialization and compression with zlib + +It is possible to use a serialization library to avoid the boilerplate. + +The following example uses Boost Serialization with the Boost zlib compression stream to reduce the size of the resulting serialized file. The example requires C++20 due to the usage of the template parameter list syntax in lambdas, but it can be adapted to less recent versions. + +```c++ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace serialization { + template + void serialize(Archive & ar, tsl::robin_map& map, const unsigned int version) { + split_free(ar, map, version); + } + + template + void save(Archive & ar, const tsl::robin_map& map, const unsigned int /*version*/) { + auto serializer = [&ar](const auto& v) { ar & v; }; + map.serialize(serializer); + } + + template + void load(Archive & ar, tsl::robin_map& map, const unsigned int /*version*/) { + auto deserializer = [&ar]() { U u; ar & u; return u; }; + map = tsl::robin_map::deserialize(deserializer); + } +}} + + +int main() { + tsl::robin_map map = {{1, -1}, {2, -2}, {3, -3}, {4, -4}}; + + + const char* file_name = "robin_map.data"; + { + std::ofstream ofs; + ofs.exceptions(ofs.badbit | ofs.failbit); + ofs.open(file_name, std::ios::binary); + + boost::iostreams::filtering_ostream fo; + fo.push(boost::iostreams::zlib_compressor()); + fo.push(ofs); + + boost::archive::binary_oarchive oa(fo); + + oa << map; + } + + { + std::ifstream ifs; + ifs.exceptions(ifs.badbit | ifs.failbit | ifs.eofbit); + ifs.open(file_name, std::ios::binary); + + boost::iostreams::filtering_istream fi; + fi.push(boost::iostreams::zlib_decompressor()); + fi.push(ifs); + + boost::archive::binary_iarchive ia(fi); + + tsl::robin_map map_deserialized; + ia >> map_deserialized; + + assert(map == map_deserialized); + } +} +``` + +### License + +The code is licensed under the MIT license, see the [LICENSE file](LICENSE) for details. diff --git a/3rdparty/robin-map/cmake/tsl-robin-mapConfig.cmake.in b/3rdparty/robin-map/cmake/tsl-robin-mapConfig.cmake.in new file mode 100644 index 00000000..d2ce2330 --- /dev/null +++ b/3rdparty/robin-map/cmake/tsl-robin-mapConfig.cmake.in @@ -0,0 +1,9 @@ +# This module sets the following variables: +# * tsl-robin-map_FOUND - true if tsl-robin-map found on the system +# * tsl-robin-map_INCLUDE_DIRS - the directory containing tsl-robin-map headers +@PACKAGE_INIT@ + +if(NOT TARGET tsl::robin_map) + include("${CMAKE_CURRENT_LIST_DIR}/tsl-robin-mapTargets.cmake") + get_target_property(tsl-robin-map_INCLUDE_DIRS tsl::robin_map INTERFACE_INCLUDE_DIRECTORIES) +endif() diff --git a/3rdparty/robin-map/include/tsl/robin_growth_policy.h b/3rdparty/robin-map/include/tsl/robin_growth_policy.h new file mode 100644 index 00000000..eba8cdfa --- /dev/null +++ b/3rdparty/robin-map/include/tsl/robin_growth_policy.h @@ -0,0 +1,406 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_GROWTH_POLICY_H +#define TSL_ROBIN_GROWTH_POLICY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TSL_DEBUG +#define tsl_rh_assert(expr) assert(expr) +#else +#define tsl_rh_assert(expr) (static_cast(0)) +#endif + +/** + * If exceptions are enabled, throw the exception passed in parameter, otherwise + * call std::terminate. + */ +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND))) && \ + !defined(TSL_NO_EXCEPTIONS) +#define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) +#else +#define TSL_RH_NO_EXCEPTIONS +#ifdef TSL_DEBUG +#include +#define TSL_RH_THROW_OR_TERMINATE(ex, msg) \ + do { \ + std::cerr << msg << std::endl; \ + std::terminate(); \ + } while (0) +#else +#define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate() +#endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define TSL_RH_LIKELY(exp) (__builtin_expect(!!(exp), true)) +#else +#define TSL_RH_LIKELY(exp) (exp) +#endif + +#define TSL_RH_UNUSED(x) static_cast(x) + +namespace tsl { +namespace rh { + +/** + * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a + * power of two. It allows the table to use a mask operation instead of a modulo + * operation to map a hash to a bucket. + * + * GrowthFactor must be a power of two >= 2. + */ +template +class power_of_two_growth_policy { + public: + /** + * Called on the hash table creation and on rehash. The number of buckets for + * the table is passed in parameter. This number is a minimum, the policy may + * update this value with a higher value if needed (but not lower). + * + * If 0 is given, min_bucket_count_in_out must still be 0 after the policy + * creation and bucket_for_hash must always return 0 in this case. + */ + explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) { + if (min_bucket_count_in_out > max_bucket_count()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + if (min_bucket_count_in_out > 0) { + min_bucket_count_in_out = + round_up_to_power_of_two(min_bucket_count_in_out); + m_mask = min_bucket_count_in_out - 1; + } else { + m_mask = 0; + } + } + + /** + * Return the bucket [0, bucket_count()) to which the hash belongs. + * If bucket_count() is 0, it must always return 0. + */ + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash & m_mask; + } + + /** + * Return the number of buckets that should be used on next growth. + */ + std::size_t next_bucket_count() const { + if ((m_mask + 1) > max_bucket_count() / GrowthFactor) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + return (m_mask + 1) * GrowthFactor; + } + + /** + * Return the maximum number of buckets supported by the policy. + */ + std::size_t max_bucket_count() const { + // Largest power of two. + return (std::numeric_limits::max() / 2) + 1; + } + + /** + * Reset the growth policy as if it was created with a bucket count of 0. + * After a clear, the policy must always return 0 when bucket_for_hash is + * called. + */ + void clear() noexcept { m_mask = 0; } + + private: + static std::size_t round_up_to_power_of_two(std::size_t value) { + if (is_power_of_two(value)) { + return value; + } + + if (value == 0) { + return 1; + } + + --value; + for (std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { + value |= value >> i; + } + + return value + 1; + } + + static constexpr bool is_power_of_two(std::size_t value) { + return value != 0 && (value & (value - 1)) == 0; + } + + protected: + static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, + "GrowthFactor must be a power of two >= 2."); + + std::size_t m_mask; +}; + +/** + * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo + * to map a hash to a bucket. Slower but it can be useful if you want a slower + * growth. + */ +template > +class mod_growth_policy { + public: + explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) { + if (min_bucket_count_in_out > max_bucket_count()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + if (min_bucket_count_in_out > 0) { + m_mod = min_bucket_count_in_out; + } else { + m_mod = 1; + } + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash % m_mod; + } + + std::size_t next_bucket_count() const { + if (m_mod == max_bucket_count()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + const double next_bucket_count = + std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR); + if (!std::isnormal(next_bucket_count)) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + if (next_bucket_count > double(max_bucket_count())) { + return max_bucket_count(); + } else { + return std::size_t(next_bucket_count); + } + } + + std::size_t max_bucket_count() const { return MAX_BUCKET_COUNT; } + + void clear() noexcept { m_mod = 1; } + + private: + static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = + 1.0 * GrowthFactor::num / GrowthFactor::den; + static const std::size_t MAX_BUCKET_COUNT = + std::size_t(double(std::numeric_limits::max() / + REHASH_SIZE_MULTIPLICATION_FACTOR)); + + static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, + "Growth factor should be >= 1.1."); + + std::size_t m_mod; +}; + +namespace detail { + +#if SIZE_MAX >= ULLONG_MAX +#define TSL_RH_NB_PRIMES 51 +#elif SIZE_MAX >= ULONG_MAX +#define TSL_RH_NB_PRIMES 40 +#else +#define TSL_RH_NB_PRIMES 23 +#endif + +static constexpr const std::array PRIMES = {{ + 1u, + 5u, + 17u, + 29u, + 37u, + 53u, + 67u, + 79u, + 97u, + 131u, + 193u, + 257u, + 389u, + 521u, + 769u, + 1031u, + 1543u, + 2053u, + 3079u, + 6151u, + 12289u, + 24593u, + 49157u, +#if SIZE_MAX >= ULONG_MAX + 98317ul, + 196613ul, + 393241ul, + 786433ul, + 1572869ul, + 3145739ul, + 6291469ul, + 12582917ul, + 25165843ul, + 50331653ul, + 100663319ul, + 201326611ul, + 402653189ul, + 805306457ul, + 1610612741ul, + 3221225473ul, + 4294967291ul, +#endif +#if SIZE_MAX >= ULLONG_MAX + 6442450939ull, + 12884901893ull, + 25769803751ull, + 51539607551ull, + 103079215111ull, + 206158430209ull, + 412316860441ull, + 824633720831ull, + 1649267441651ull, + 3298534883309ull, + 6597069766657ull, +#endif +}}; + +template +static constexpr std::size_t mod(std::size_t hash) { + return hash % PRIMES[IPrime]; +} + +// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for +// faster modulo as the compiler can optimize the modulo code better with a +// constant known at the compilation. +static constexpr const std::array + MOD_PRIME = {{ + &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, + &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, &mod<11>, + &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, + &mod<18>, &mod<19>, &mod<20>, &mod<21>, &mod<22>, +#if SIZE_MAX >= ULONG_MAX + &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, + &mod<29>, &mod<30>, &mod<31>, &mod<32>, &mod<33>, &mod<34>, + &mod<35>, &mod<36>, &mod<37>, &mod<38>, &mod<39>, +#endif +#if SIZE_MAX >= ULLONG_MAX + &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>, + &mod<46>, &mod<47>, &mod<48>, &mod<49>, &mod<50>, +#endif + }}; + +} // namespace detail + +/** + * Grow the hash table by using prime numbers as bucket count. Slower than + * tsl::rh::power_of_two_growth_policy in general but will probably distribute + * the values around better in the buckets with a poor hash function. + * + * To allow the compiler to optimize the modulo operation, a lookup table is + * used with constant primes numbers. + * + * With a switch the code would look like: + * \code + * switch(iprime) { // iprime is the current prime of the hash table + * case 0: hash % 5ul; + * break; + * case 1: hash % 17ul; + * break; + * case 2: hash % 29ul; + * break; + * ... + * } + * \endcode + * + * Due to the constant variable in the modulo the compiler is able to optimize + * the operation by a series of multiplications, substractions and shifts. + * + * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) + * * 5' in a 64 bits environment. + */ +class prime_growth_policy { + public: + explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) { + auto it_prime = std::lower_bound( + detail::PRIMES.begin(), detail::PRIMES.end(), min_bucket_count_in_out); + if (it_prime == detail::PRIMES.end()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + m_iprime = static_cast( + std::distance(detail::PRIMES.begin(), it_prime)); + if (min_bucket_count_in_out > 0) { + min_bucket_count_in_out = *it_prime; + } else { + min_bucket_count_in_out = 0; + } + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return detail::MOD_PRIME[m_iprime](hash); + } + + std::size_t next_bucket_count() const { + if (m_iprime + 1 >= detail::PRIMES.size()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The hash table exceeds its maximum size."); + } + + return detail::PRIMES[m_iprime + 1]; + } + + std::size_t max_bucket_count() const { return detail::PRIMES.back(); } + + void clear() noexcept { m_iprime = 0; } + + private: + unsigned int m_iprime; + + static_assert(std::numeric_limits::max() >= + detail::PRIMES.size(), + "The type of m_iprime is not big enough."); +}; + +} // namespace rh +} // namespace tsl + +#endif diff --git a/3rdparty/robin-map/include/tsl/robin_hash.h b/3rdparty/robin-map/include/tsl/robin_hash.h new file mode 100644 index 00000000..5fdc07f9 --- /dev/null +++ b/3rdparty/robin-map/include/tsl/robin_hash.h @@ -0,0 +1,1639 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_HASH_H +#define TSL_ROBIN_HASH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "robin_growth_policy.h" + +namespace tsl { + +namespace detail_robin_hash { + +template +struct make_void { + using type = void; +}; + +template +struct has_is_transparent : std::false_type {}; + +template +struct has_is_transparent::type> + : std::true_type {}; + +template +struct is_power_of_two_policy : std::false_type {}; + +template +struct is_power_of_two_policy> + : std::true_type {}; + +// Only available in C++17, we need to be compatible with C++11 +template +const T& clamp(const T& v, const T& lo, const T& hi) { + return std::min(hi, std::max(lo, v)); +} + +template +static T numeric_cast(U value, + const char* error_message = "numeric_cast() failed.") { + T ret = static_cast(value); + if (static_cast(ret) != value) { + TSL_RH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + const bool is_same_signedness = + (std::is_unsigned::value && std::is_unsigned::value) || + (std::is_signed::value && std::is_signed::value); + if (!is_same_signedness && (ret < T{}) != (value < U{})) { + TSL_RH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + return ret; +} + +template +static T deserialize_value(Deserializer& deserializer) { + // MSVC < 2017 is not conformant, circumvent the problem by removing the + // template keyword +#if defined(_MSC_VER) && _MSC_VER < 1910 + return deserializer.Deserializer::operator()(); +#else + return deserializer.Deserializer::template operator()(); +#endif +} + +/** + * Fixed size type used to represent size_type values on serialization. Need to + * be big enough to represent a std::size_t on 32 and 64 bits platforms, and + * must be the same size on both platforms. + */ +using slz_size_type = std::uint64_t; +static_assert(std::numeric_limits::max() >= + std::numeric_limits::max(), + "slz_size_type must be >= std::size_t"); + +using truncated_hash_type = std::uint32_t; + +/** + * Helper class that stores a truncated hash if StoreHash is true and nothing + * otherwise. + */ +template +class bucket_entry_hash { + public: + bool bucket_hash_equal(std::size_t /*hash*/) const noexcept { return true; } + + truncated_hash_type truncated_hash() const noexcept { return 0; } + + protected: + void set_hash(truncated_hash_type /*hash*/) noexcept {} +}; + +template <> +class bucket_entry_hash { + public: + bool bucket_hash_equal(std::size_t hash) const noexcept { + return m_hash == truncated_hash_type(hash); + } + + truncated_hash_type truncated_hash() const noexcept { return m_hash; } + + protected: + void set_hash(truncated_hash_type hash) noexcept { + m_hash = truncated_hash_type(hash); + } + + private: + truncated_hash_type m_hash; +}; + +/** + * Each bucket entry has: + * - A value of type `ValueType`. + * - An integer to store how far the value of the bucket, if any, is from its + * ideal bucket (ex: if the current bucket 5 has the value 'foo' and + * `hash('foo') % nb_buckets` == 3, `dist_from_ideal_bucket()` will return 2 as + * the current value of the bucket is two buckets away from its ideal bucket) If + * there is no value in the bucket (i.e. `empty()` is true) + * `dist_from_ideal_bucket()` will be < 0. + * - A marker which tells us if the bucket is the last bucket of the bucket + * array (useful for the iterator of the hash table). + * - If `StoreHash` is true, 32 bits of the hash of the value, if any, are also + * stored in the bucket. If the size of the hash is more than 32 bits, it is + * truncated. We don't store the full hash as storing the hash is a potential + * opportunity to use the unused space due to the alignment of the bucket_entry + * structure. We can thus potentially store the hash without any extra space + * (which would not be possible with 64 bits of the hash). + */ +template +class bucket_entry : public bucket_entry_hash { + using bucket_hash = bucket_entry_hash; + + public: + using value_type = ValueType; + using distance_type = std::int16_t; + + bucket_entry() noexcept + : bucket_hash(), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(false) { + tsl_rh_assert(empty()); + } + + bucket_entry(bool last_bucket) noexcept + : bucket_hash(), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(last_bucket) { + tsl_rh_assert(empty()); + } + + bucket_entry(const bucket_entry& other) noexcept( + std::is_nothrow_copy_constructible::value) + : bucket_hash(other), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) { + if (!other.empty()) { + ::new (static_cast(std::addressof(m_value))) + value_type(other.value()); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + tsl_rh_assert(empty() == other.empty()); + } + + /** + * Never really used, but still necessary as we must call resize on an empty + * `std::vector`. and we need to support move-only types. See + * robin_hash constructor for details. + */ + bucket_entry(bucket_entry&& other) noexcept( + std::is_nothrow_move_constructible::value) + : bucket_hash(std::move(other)), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) { + if (!other.empty()) { + ::new (static_cast(std::addressof(m_value))) + value_type(std::move(other.value())); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + tsl_rh_assert(empty() == other.empty()); + } + + bucket_entry& operator=(const bucket_entry& other) noexcept( + std::is_nothrow_copy_constructible::value) { + if (this != &other) { + clear(); + + bucket_hash::operator=(other); + if (!other.empty()) { + ::new (static_cast(std::addressof(m_value))) + value_type(other.value()); + } + + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + m_last_bucket = other.m_last_bucket; + } + + return *this; + } + + bucket_entry& operator=(bucket_entry&&) = delete; + + ~bucket_entry() noexcept { clear(); } + + void clear() noexcept { + if (!empty()) { + destroy_value(); + m_dist_from_ideal_bucket = EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + } + + bool empty() const noexcept { + return m_dist_from_ideal_bucket == EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + + value_type& value() noexcept { + tsl_rh_assert(!empty()); +#if defined(__cplusplus) && __cplusplus >= 201703L + return *std::launder( + reinterpret_cast(std::addressof(m_value))); +#else + return *reinterpret_cast(std::addressof(m_value)); +#endif + } + + const value_type& value() const noexcept { + tsl_rh_assert(!empty()); +#if defined(__cplusplus) && __cplusplus >= 201703L + return *std::launder( + reinterpret_cast(std::addressof(m_value))); +#else + return *reinterpret_cast(std::addressof(m_value)); +#endif + } + + distance_type dist_from_ideal_bucket() const noexcept { + return m_dist_from_ideal_bucket; + } + + bool last_bucket() const noexcept { return m_last_bucket; } + + void set_as_last_bucket() noexcept { m_last_bucket = true; } + + template + void set_value_of_empty_bucket(distance_type dist_from_ideal_bucket, + truncated_hash_type hash, + Args&&... value_type_args) { + tsl_rh_assert(dist_from_ideal_bucket >= 0); + tsl_rh_assert(empty()); + + ::new (static_cast(std::addressof(m_value))) + value_type(std::forward(value_type_args)...); + this->set_hash(hash); + m_dist_from_ideal_bucket = dist_from_ideal_bucket; + + tsl_rh_assert(!empty()); + } + + void swap_with_value_in_bucket(distance_type& dist_from_ideal_bucket, + truncated_hash_type& hash, value_type& value) { + tsl_rh_assert(!empty()); + tsl_rh_assert(dist_from_ideal_bucket > m_dist_from_ideal_bucket); + + using std::swap; + swap(value, this->value()); + swap(dist_from_ideal_bucket, m_dist_from_ideal_bucket); + + if (StoreHash) { + const truncated_hash_type tmp_hash = this->truncated_hash(); + this->set_hash(hash); + hash = tmp_hash; + } else { + // Avoid warning of unused variable if StoreHash is false + TSL_RH_UNUSED(hash); + } + } + + static truncated_hash_type truncate_hash(std::size_t hash) noexcept { + return truncated_hash_type(hash); + } + + private: + void destroy_value() noexcept { + tsl_rh_assert(!empty()); + value().~value_type(); + } + + public: + static const distance_type EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET = -1; + static const distance_type DIST_FROM_IDEAL_BUCKET_LIMIT = 8192; + static_assert(DIST_FROM_IDEAL_BUCKET_LIMIT <= + std::numeric_limits::max() - 1, + "DIST_FROM_IDEAL_BUCKET_LIMIT must be <= " + "std::numeric_limits::max() - 1."); + + private: + distance_type m_dist_from_ideal_bucket; + bool m_last_bucket; + alignas(value_type) unsigned char m_value[sizeof(value_type)]; +}; + +/** + * Internal common class used by `robin_map` and `robin_set`. + * + * ValueType is what will be stored by `robin_hash` (usually `std::pair` + * for map and `Key` for set). + * + * `KeySelect` should be a `FunctionObject` which takes a `ValueType` in + * parameter and returns a reference to the key. + * + * `ValueSelect` should be a `FunctionObject` which takes a `ValueType` in + * parameter and returns a reference to the value. `ValueSelect` should be void + * if there is no value (in a set for example). + * + * The strong exception guarantee only holds if the expression + * `std::is_nothrow_swappable::value && + * std::is_nothrow_move_constructible::value` is true. + * + * Behaviour is undefined if the destructor of `ValueType` throws. + */ +template +class robin_hash : private Hash, private KeyEqual, private GrowthPolicy { + private: + template + using has_mapped_type = + typename std::integral_constant::value>; + + static_assert( + noexcept(std::declval().bucket_for_hash(std::size_t(0))), + "GrowthPolicy::bucket_for_hash must be noexcept."); + static_assert(noexcept(std::declval().clear()), + "GrowthPolicy::clear must be noexcept."); + + public: + template + class robin_iterator; + + using key_type = typename KeySelect::key_type; + using value_type = ValueType; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = robin_iterator; + using const_iterator = robin_iterator; + + private: + /** + * Either store the hash because we are asked by the `StoreHash` template + * parameter or store the hash because it doesn't cost us anything in size and + * can be used to speed up rehash. + */ + static constexpr bool STORE_HASH = + StoreHash || + ((sizeof(tsl::detail_robin_hash::bucket_entry) == + sizeof(tsl::detail_robin_hash::bucket_entry)) && + (sizeof(std::size_t) == sizeof(truncated_hash_type) || + is_power_of_two_policy::value) && + // Don't store the hash for primitive types with default hash. + (!std::is_arithmetic::value || + !std::is_same>::value)); + + /** + * Only use the stored hash on lookup if we are explicitly asked. We are not + * sure how slow the KeyEqual operation is. An extra comparison may slow + * things down with a fast KeyEqual. + */ + static constexpr bool USE_STORED_HASH_ON_LOOKUP = StoreHash; + + /** + * We can only use the hash on rehash if the size of the hash type is the same + * as the stored one or if we use a power of two modulo. In the case of the + * power of two modulo, we just mask the least significant bytes, we just have + * to check that the truncated_hash_type didn't truncated more bytes. + */ + static bool USE_STORED_HASH_ON_REHASH(size_type bucket_count) { + if (STORE_HASH && sizeof(std::size_t) == sizeof(truncated_hash_type)) { + TSL_RH_UNUSED(bucket_count); + return true; + } else if (STORE_HASH && is_power_of_two_policy::value) { + return bucket_count == 0 || + (bucket_count - 1) <= + std::numeric_limits::max(); + } else { + TSL_RH_UNUSED(bucket_count); + return false; + } + } + + using bucket_entry = + tsl::detail_robin_hash::bucket_entry; + using distance_type = typename bucket_entry::distance_type; + + using buckets_allocator = typename std::allocator_traits< + allocator_type>::template rebind_alloc; + using buckets_container_type = std::vector; + + public: + /** + * The 'operator*()' and 'operator->()' methods return a const reference and + * const pointer respectively to the stored value type. + * + * In case of a map, to get a mutable reference to the value associated to a + * key (the '.second' in the stored pair), you have to call 'value()'. + * + * The main reason for this is that if we returned a `std::pair&` + * instead of a `const std::pair&`, the user may modify the key which + * will put the map in a undefined state. + */ + template + class robin_iterator { + friend class robin_hash; + + private: + using bucket_entry_ptr = + typename std::conditional::type; + + robin_iterator(bucket_entry_ptr bucket) noexcept : m_bucket(bucket) {} + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const typename robin_hash::value_type; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + + robin_iterator() noexcept {} + + // Copy constructor from iterator to const_iterator. + template ::type* = nullptr> + robin_iterator(const robin_iterator& other) noexcept + : m_bucket(other.m_bucket) {} + + robin_iterator(const robin_iterator& other) = default; + robin_iterator(robin_iterator&& other) = default; + robin_iterator& operator=(const robin_iterator& other) = default; + robin_iterator& operator=(robin_iterator&& other) = default; + + const typename robin_hash::key_type& key() const { + return KeySelect()(m_bucket->value()); + } + + template ::value && + IsConst>::type* = nullptr> + const typename U::value_type& value() const { + return U()(m_bucket->value()); + } + + template ::value && + !IsConst>::type* = nullptr> + typename U::value_type& value() const { + return U()(m_bucket->value()); + } + + reference operator*() const { return m_bucket->value(); } + + pointer operator->() const { return std::addressof(m_bucket->value()); } + + robin_iterator& operator++() { + while (true) { + if (m_bucket->last_bucket()) { + ++m_bucket; + return *this; + } + + ++m_bucket; + if (!m_bucket->empty()) { + return *this; + } + } + } + + robin_iterator operator++(int) { + robin_iterator tmp(*this); + ++*this; + + return tmp; + } + + friend bool operator==(const robin_iterator& lhs, + const robin_iterator& rhs) { + return lhs.m_bucket == rhs.m_bucket; + } + + friend bool operator!=(const robin_iterator& lhs, + const robin_iterator& rhs) { + return !(lhs == rhs); + } + + private: + bucket_entry_ptr m_bucket; + }; + + public: +#if defined(__cplusplus) && __cplusplus >= 201402L + robin_hash(size_type bucket_count, const Hash& hash, const KeyEqual& equal, + const Allocator& alloc, + float min_load_factor = DEFAULT_MIN_LOAD_FACTOR, + float max_load_factor = DEFAULT_MAX_LOAD_FACTOR) + : Hash(hash), + KeyEqual(equal), + GrowthPolicy(bucket_count), + m_buckets_data(bucket_count, alloc), + m_buckets(m_buckets_data.empty() ? static_empty_bucket_ptr() + : m_buckets_data.data()), + m_bucket_count(bucket_count), + m_nb_elements(0), + m_grow_on_next_insert(false), + m_try_shrink_on_next_insert(false) { + if (bucket_count > max_bucket_count()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The map exceeds its maximum bucket count."); + } + + if (m_bucket_count > 0) { + tsl_rh_assert(!m_buckets_data.empty()); + m_buckets_data.back().set_as_last_bucket(); + } + + this->min_load_factor(min_load_factor); + this->max_load_factor(max_load_factor); + } +#else + /** + * C++11 doesn't support the creation of a std::vector with a custom allocator + * and 'count' default-inserted elements. The needed contructor `explicit + * vector(size_type count, const Allocator& alloc = Allocator());` is only + * available in C++14 and later. We thus must resize after using the + * `vector(const Allocator& alloc)` constructor. + * + * We can't use `vector(size_type count, const T& value, const Allocator& + * alloc)` as it requires the value T to be copyable. + */ + robin_hash(size_type bucket_count, const Hash& hash, const KeyEqual& equal, + const Allocator& alloc, + float min_load_factor = DEFAULT_MIN_LOAD_FACTOR, + float max_load_factor = DEFAULT_MAX_LOAD_FACTOR) + : Hash(hash), + KeyEqual(equal), + GrowthPolicy(bucket_count), + m_buckets_data(alloc), + m_buckets(static_empty_bucket_ptr()), + m_bucket_count(bucket_count), + m_nb_elements(0), + m_grow_on_next_insert(false), + m_try_shrink_on_next_insert(false) { + if (bucket_count > max_bucket_count()) { + TSL_RH_THROW_OR_TERMINATE(std::length_error, + "The map exceeds its maximum bucket count."); + } + + if (m_bucket_count > 0) { + m_buckets_data.resize(m_bucket_count); + m_buckets = m_buckets_data.data(); + + tsl_rh_assert(!m_buckets_data.empty()); + m_buckets_data.back().set_as_last_bucket(); + } + + this->min_load_factor(min_load_factor); + this->max_load_factor(max_load_factor); + } +#endif + + robin_hash(const robin_hash& other) + : Hash(other), + KeyEqual(other), + GrowthPolicy(other), + m_buckets_data(other.m_buckets_data), + m_buckets(m_buckets_data.empty() ? static_empty_bucket_ptr() + : m_buckets_data.data()), + m_bucket_count(other.m_bucket_count), + m_nb_elements(other.m_nb_elements), + m_load_threshold(other.m_load_threshold), + m_min_load_factor(other.m_min_load_factor), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert), + m_try_shrink_on_next_insert(other.m_try_shrink_on_next_insert) {} + + robin_hash(robin_hash&& other) noexcept( + std::is_nothrow_move_constructible< + Hash>::value&& std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value) + : Hash(std::move(static_cast(other))), + KeyEqual(std::move(static_cast(other))), + GrowthPolicy(std::move(static_cast(other))), + m_buckets_data(std::move(other.m_buckets_data)), + m_buckets(m_buckets_data.empty() ? static_empty_bucket_ptr() + : m_buckets_data.data()), + m_bucket_count(other.m_bucket_count), + m_nb_elements(other.m_nb_elements), + m_load_threshold(other.m_load_threshold), + m_min_load_factor(other.m_min_load_factor), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert), + m_try_shrink_on_next_insert(other.m_try_shrink_on_next_insert) { + other.clear_and_shrink(); + } + + robin_hash& operator=(const robin_hash& other) { + if (&other != this) { + Hash::operator=(other); + KeyEqual::operator=(other); + GrowthPolicy::operator=(other); + + m_buckets_data = other.m_buckets_data; + m_buckets = m_buckets_data.empty() ? static_empty_bucket_ptr() + : m_buckets_data.data(); + m_bucket_count = other.m_bucket_count; + m_nb_elements = other.m_nb_elements; + + m_load_threshold = other.m_load_threshold; + m_min_load_factor = other.m_min_load_factor; + m_max_load_factor = other.m_max_load_factor; + + m_grow_on_next_insert = other.m_grow_on_next_insert; + m_try_shrink_on_next_insert = other.m_try_shrink_on_next_insert; + } + + return *this; + } + + robin_hash& operator=(robin_hash&& other) { + other.swap(*this); + other.clear_and_shrink(); + + return *this; + } + + allocator_type get_allocator() const { + return m_buckets_data.get_allocator(); + } + + /* + * Iterators + */ + iterator begin() noexcept { + std::size_t i = 0; + while (i < m_bucket_count && m_buckets[i].empty()) { + i++; + } + + return iterator(m_buckets + i); + } + + const_iterator begin() const noexcept { return cbegin(); } + + const_iterator cbegin() const noexcept { + std::size_t i = 0; + while (i < m_bucket_count && m_buckets[i].empty()) { + i++; + } + + return const_iterator(m_buckets + i); + } + + iterator end() noexcept { return iterator(m_buckets + m_bucket_count); } + + const_iterator end() const noexcept { return cend(); } + + const_iterator cend() const noexcept { + return const_iterator(m_buckets + m_bucket_count); + } + + /* + * Capacity + */ + bool empty() const noexcept { return m_nb_elements == 0; } + + size_type size() const noexcept { return m_nb_elements; } + + size_type max_size() const noexcept { return m_buckets_data.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { + if (m_min_load_factor > 0.0f) { + clear_and_shrink(); + } else { + for (auto& bucket : m_buckets_data) { + bucket.clear(); + } + + m_nb_elements = 0; + m_grow_on_next_insert = false; + } + } + + template + std::pair insert(P&& value) { + return insert_impl(KeySelect()(value), std::forward

(value)); + } + + template + iterator insert_hint(const_iterator hint, P&& value) { + if (hint != cend() && + compare_keys(KeySelect()(*hint), KeySelect()(value))) { + return mutable_iterator(hint); + } + + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + if (std::is_base_of< + std::forward_iterator_tag, + typename std::iterator_traits::iterator_category>::value) { + const auto nb_elements_insert = std::distance(first, last); + const size_type nb_free_buckets = m_load_threshold - size(); + tsl_rh_assert(m_load_threshold >= size()); + + if (nb_elements_insert > 0 && + nb_free_buckets < size_type(nb_elements_insert)) { + reserve(size() + size_type(nb_elements_insert)); + } + } + + for (; first != last; ++first) { + insert(*first); + } + } + + template + std::pair insert_or_assign(K&& key, M&& obj) { + auto it = try_emplace(std::forward(key), std::forward(obj)); + if (!it.second) { + it.first.value() = std::forward(obj); + } + + return it; + } + + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { + if (hint != cend() && compare_keys(KeySelect()(*hint), key)) { + auto it = mutable_iterator(hint); + it.value() = std::forward(obj); + + return it; + } + + return insert_or_assign(std::forward(key), std::forward(obj)).first; + } + + template + std::pair emplace(Args&&... args) { + return insert(value_type(std::forward(args)...)); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return insert_hint(hint, value_type(std::forward(args)...)); + } + + template + std::pair try_emplace(K&& key, Args&&... args) { + return insert_impl(key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); + } + + template + iterator try_emplace_hint(const_iterator hint, K&& key, Args&&... args) { + if (hint != cend() && compare_keys(KeySelect()(*hint), key)) { + return mutable_iterator(hint); + } + + return try_emplace(std::forward(key), std::forward(args)...).first; + } + + /** + * Here to avoid `template size_type erase(const K& key)` being used + * when we use an `iterator` instead of a `const_iterator`. + */ + iterator erase(iterator pos) { + erase_from_bucket(pos); + + /** + * Erase bucket used a backward shift after clearing the bucket. + * Check if there is a new value in the bucket, if not get the next + * non-empty. + */ + if (pos.m_bucket->empty()) { + ++pos; + } + + m_try_shrink_on_next_insert = true; + + return pos; + } + + iterator erase(const_iterator pos) { return erase(mutable_iterator(pos)); } + + iterator erase(const_iterator first, const_iterator last) { + if (first == last) { + return mutable_iterator(first); + } + + auto first_mutable = mutable_iterator(first); + auto last_mutable = mutable_iterator(last); + for (auto it = first_mutable.m_bucket; it != last_mutable.m_bucket; ++it) { + if (!it->empty()) { + it->clear(); + m_nb_elements--; + } + } + + if (last_mutable == end()) { + m_try_shrink_on_next_insert = true; + return end(); + } + + /* + * Backward shift on the values which come after the deleted values. + * We try to move the values closer to their ideal bucket. + */ + std::size_t icloser_bucket = + static_cast(first_mutable.m_bucket - m_buckets); + std::size_t ito_move_closer_value = + static_cast(last_mutable.m_bucket - m_buckets); + tsl_rh_assert(ito_move_closer_value > icloser_bucket); + + const std::size_t ireturn_bucket = + ito_move_closer_value - + std::min( + ito_move_closer_value - icloser_bucket, + std::size_t( + m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + while (ito_move_closer_value < m_bucket_count && + m_buckets[ito_move_closer_value].dist_from_ideal_bucket() > 0) { + icloser_bucket = + ito_move_closer_value - + std::min( + ito_move_closer_value - icloser_bucket, + std::size_t( + m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + tsl_rh_assert(m_buckets[icloser_bucket].empty()); + const distance_type new_distance = distance_type( + m_buckets[ito_move_closer_value].dist_from_ideal_bucket() - + (ito_move_closer_value - icloser_bucket)); + m_buckets[icloser_bucket].set_value_of_empty_bucket( + new_distance, m_buckets[ito_move_closer_value].truncated_hash(), + std::move(m_buckets[ito_move_closer_value].value())); + m_buckets[ito_move_closer_value].clear(); + + ++icloser_bucket; + ++ito_move_closer_value; + } + + m_try_shrink_on_next_insert = true; + + return iterator(m_buckets + ireturn_bucket); + } + + template + size_type erase(const K& key) { + return erase(key, hash_key(key)); + } + + template + size_type erase(const K& key, std::size_t hash) { + auto it = find(key, hash); + if (it != end()) { + erase_from_bucket(it); + m_try_shrink_on_next_insert = true; + + return 1; + } else { + return 0; + } + } + + void swap(robin_hash& other) { + using std::swap; + + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(m_buckets_data, other.m_buckets_data); + swap(m_buckets, other.m_buckets); + swap(m_bucket_count, other.m_bucket_count); + swap(m_nb_elements, other.m_nb_elements); + swap(m_load_threshold, other.m_load_threshold); + swap(m_min_load_factor, other.m_min_load_factor); + swap(m_max_load_factor, other.m_max_load_factor); + swap(m_grow_on_next_insert, other.m_grow_on_next_insert); + swap(m_try_shrink_on_next_insert, other.m_try_shrink_on_next_insert); + } + + /* + * Lookup + */ + template ::value>::type* = nullptr> + typename U::value_type& at(const K& key) { + return at(key, hash_key(key)); + } + + template ::value>::type* = nullptr> + typename U::value_type& at(const K& key, std::size_t hash) { + return const_cast( + static_cast(this)->at(key, hash)); + } + + template ::value>::type* = nullptr> + const typename U::value_type& at(const K& key) const { + return at(key, hash_key(key)); + } + + template ::value>::type* = nullptr> + const typename U::value_type& at(const K& key, std::size_t hash) const { + auto it = find(key, hash); + if (it != cend()) { + return it.value(); + } else { + TSL_RH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find key."); + } + } + + template ::value>::type* = nullptr> + typename U::value_type& operator[](K&& key) { + return try_emplace(std::forward(key)).first.value(); + } + + template + size_type count(const K& key) const { + return count(key, hash_key(key)); + } + + template + size_type count(const K& key, std::size_t hash) const { + if (find(key, hash) != cend()) { + return 1; + } else { + return 0; + } + } + + template + iterator find(const K& key) { + return find_impl(key, hash_key(key)); + } + + template + iterator find(const K& key, std::size_t hash) { + return find_impl(key, hash); + } + + template + const_iterator find(const K& key) const { + return find_impl(key, hash_key(key)); + } + + template + const_iterator find(const K& key, std::size_t hash) const { + return find_impl(key, hash); + } + + template + bool contains(const K& key) const { + return contains(key, hash_key(key)); + } + + template + bool contains(const K& key, std::size_t hash) const { + return count(key, hash) != 0; + } + + template + std::pair equal_range(const K& key) { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) { + iterator it = find(key, hash); + return std::make_pair(it, (it == end()) ? it : std::next(it)); + } + + template + std::pair equal_range(const K& key) const { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range( + const K& key, std::size_t hash) const { + const_iterator it = find(key, hash); + return std::make_pair(it, (it == cend()) ? it : std::next(it)); + } + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_bucket_count; } + + size_type max_bucket_count() const { + return std::min(GrowthPolicy::max_bucket_count(), + m_buckets_data.max_size()); + } + + /* + * Hash policy + */ + float load_factor() const { + if (bucket_count() == 0) { + return 0; + } + + return float(m_nb_elements) / float(bucket_count()); + } + + float min_load_factor() const { return m_min_load_factor; } + + float max_load_factor() const { return m_max_load_factor; } + + void min_load_factor(float ml) { + m_min_load_factor = clamp(ml, float(MINIMUM_MIN_LOAD_FACTOR), + float(MAXIMUM_MIN_LOAD_FACTOR)); + } + + void max_load_factor(float ml) { + m_max_load_factor = clamp(ml, float(MINIMUM_MAX_LOAD_FACTOR), + float(MAXIMUM_MAX_LOAD_FACTOR)); + m_load_threshold = size_type(float(bucket_count()) * m_max_load_factor); + tsl_rh_assert(bucket_count() == 0 || m_load_threshold < bucket_count()); + } + + void rehash(size_type count_) { + count_ = std::max(count_, + size_type(std::ceil(float(size()) / max_load_factor()))); + rehash_impl(count_); + } + + void reserve(size_type count_) { + rehash(size_type(std::ceil(float(count_) / max_load_factor()))); + } + + /* + * Observers + */ + hasher hash_function() const { return static_cast(*this); } + + key_equal key_eq() const { return static_cast(*this); } + + /* + * Other + */ + iterator mutable_iterator(const_iterator pos) { + return iterator(const_cast(pos.m_bucket)); + } + + template + void serialize(Serializer& serializer) const { + serialize_impl(serializer); + } + + template + void deserialize(Deserializer& deserializer, bool hash_compatible) { + deserialize_impl(deserializer, hash_compatible); + } + + private: + template + std::size_t hash_key(const K& key) const { + return Hash::operator()(key); + } + + template + bool compare_keys(const K1& key1, const K2& key2) const { + return KeyEqual::operator()(key1, key2); + } + + std::size_t bucket_for_hash(std::size_t hash) const { + const std::size_t bucket = GrowthPolicy::bucket_for_hash(hash); + tsl_rh_assert(bucket < m_bucket_count || + (bucket == 0 && m_bucket_count == 0)); + + return bucket; + } + + template ::value>::type* = + nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_rh_assert(index < bucket_count()); + + return (index + 1) & this->m_mask; + } + + template ::value>::type* = + nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_rh_assert(index < bucket_count()); + + index++; + return (index != bucket_count()) ? index : 0; + } + + template + iterator find_impl(const K& key, std::size_t hash) { + return mutable_iterator( + static_cast(this)->find(key, hash)); + } + + template + const_iterator find_impl(const K& key, std::size_t hash) const { + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while (dist_from_ideal_bucket <= + m_buckets[ibucket].dist_from_ideal_bucket()) { + if (TSL_RH_LIKELY( + (!USE_STORED_HASH_ON_LOOKUP || + m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key))) { + return const_iterator(m_buckets + ibucket); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + return cend(); + } + + void erase_from_bucket(iterator pos) { + pos.m_bucket->clear(); + m_nb_elements--; + + /** + * Backward shift, swap the empty bucket, previous_ibucket, with the values + * on its right, ibucket, until we cross another empty bucket or if the + * other bucket has a distance_from_ideal_bucket == 0. + * + * We try to move the values closer to their ideal bucket. + */ + std::size_t previous_ibucket = + static_cast(pos.m_bucket - m_buckets); + std::size_t ibucket = next_bucket(previous_ibucket); + + while (m_buckets[ibucket].dist_from_ideal_bucket() > 0) { + tsl_rh_assert(m_buckets[previous_ibucket].empty()); + + const distance_type new_distance = + distance_type(m_buckets[ibucket].dist_from_ideal_bucket() - 1); + m_buckets[previous_ibucket].set_value_of_empty_bucket( + new_distance, m_buckets[ibucket].truncated_hash(), + std::move(m_buckets[ibucket].value())); + m_buckets[ibucket].clear(); + + previous_ibucket = ibucket; + ibucket = next_bucket(ibucket); + } + } + + template + std::pair insert_impl(const K& key, + Args&&... value_type_args) { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while (dist_from_ideal_bucket <= + m_buckets[ibucket].dist_from_ideal_bucket()) { + if ((!USE_STORED_HASH_ON_LOOKUP || + m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key)) { + return std::make_pair(iterator(m_buckets + ibucket), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + while (rehash_on_extreme_load(dist_from_ideal_bucket)) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + + while (dist_from_ideal_bucket <= + m_buckets[ibucket].dist_from_ideal_bucket()) { + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + } + + if (m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket( + dist_from_ideal_bucket, bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } else { + insert_value(ibucket, dist_from_ideal_bucket, + bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } + + m_nb_elements++; + /* + * The value will be inserted in ibucket in any case, either because it was + * empty or by stealing the bucket (robin hood). + */ + return std::make_pair(iterator(m_buckets + ibucket), true); + } + + template + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, Args&&... value_type_args) { + value_type value(std::forward(value_type_args)...); + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) { + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + /* + * We don't use `value_type&& value` as last argument due to a bug in MSVC + * when `value_type` is a pointer, The compiler is not able to see the + * difference between `std::string*` and `std::string*&&` resulting in a + * compilation error. + * + * The `value` will be in a moved state at the end of the function. + */ + void insert_value_impl(std::size_t ibucket, + distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type& value) { + tsl_rh_assert(dist_from_ideal_bucket > + m_buckets[ibucket].dist_from_ideal_bucket()); + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, + value); + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + + while (!m_buckets[ibucket].empty()) { + if (dist_from_ideal_bucket > + m_buckets[ibucket].dist_from_ideal_bucket()) { + if (dist_from_ideal_bucket > + bucket_entry::DIST_FROM_IDEAL_BUCKET_LIMIT) { + /** + * The number of probes is really high, rehash the map on the next + * insert. Difficult to do now as rehash may throw an exception. + */ + m_grow_on_next_insert = true; + } + + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, + hash, value); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, hash, + std::move(value)); + } + + void rehash_impl(size_type count_) { + robin_hash new_table(count_, static_cast(*this), + static_cast(*this), get_allocator(), + m_min_load_factor, m_max_load_factor); + tsl_rh_assert(size() <= new_table.m_load_threshold); + + const bool use_stored_hash = + USE_STORED_HASH_ON_REHASH(new_table.bucket_count()); + for (auto& bucket : m_buckets_data) { + if (bucket.empty()) { + continue; + } + + const std::size_t hash = + use_stored_hash ? bucket.truncated_hash() + : new_table.hash_key(KeySelect()(bucket.value())); + + new_table.insert_value_on_rehash(new_table.bucket_for_hash(hash), 0, + bucket_entry::truncate_hash(hash), + std::move(bucket.value())); + } + + new_table.m_nb_elements = m_nb_elements; + new_table.swap(*this); + } + + void clear_and_shrink() noexcept { + GrowthPolicy::clear(); + m_buckets_data.clear(); + m_buckets = static_empty_bucket_ptr(); + m_bucket_count = 0; + m_nb_elements = 0; + m_load_threshold = 0; + m_grow_on_next_insert = false; + m_try_shrink_on_next_insert = false; + } + + void insert_value_on_rehash(std::size_t ibucket, + distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) { + while (true) { + if (dist_from_ideal_bucket > + m_buckets[ibucket].dist_from_ideal_bucket()) { + if (m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, + hash, std::move(value)); + return; + } else { + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, + hash, value); + } + } + + dist_from_ideal_bucket++; + ibucket = next_bucket(ibucket); + } + } + + /** + * Grow the table if m_grow_on_next_insert is true or we reached the + * max_load_factor. Shrink the table if m_try_shrink_on_next_insert is true + * (an erase occurred) and we're below the min_load_factor. + * + * Return true if the table has been rehashed. + */ + bool rehash_on_extreme_load(distance_type curr_dist_from_ideal_bucket) { + if (m_grow_on_next_insert || + curr_dist_from_ideal_bucket > + bucket_entry::DIST_FROM_IDEAL_BUCKET_LIMIT || + size() >= m_load_threshold) { + rehash_impl(GrowthPolicy::next_bucket_count()); + m_grow_on_next_insert = false; + + return true; + } + + if (m_try_shrink_on_next_insert) { + m_try_shrink_on_next_insert = false; + if (m_min_load_factor != 0.0f && load_factor() < m_min_load_factor) { + reserve(size() + 1); + + return true; + } + } + + return false; + } + + template + void serialize_impl(Serializer& serializer) const { + const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION; + serializer(version); + + // Indicate if the truncated hash of each bucket is stored. Use a + // std::int16_t instead of a bool to avoid the need for the serializer to + // support an extra 'bool' type. + const std::int16_t hash_stored_for_bucket = + static_cast(STORE_HASH); + serializer(hash_stored_for_bucket); + + const slz_size_type nb_elements = m_nb_elements; + serializer(nb_elements); + + const slz_size_type bucket_count = m_buckets_data.size(); + serializer(bucket_count); + + const float min_load_factor = m_min_load_factor; + serializer(min_load_factor); + + const float max_load_factor = m_max_load_factor; + serializer(max_load_factor); + + for (const bucket_entry& bucket : m_buckets_data) { + if (bucket.empty()) { + const std::int16_t empty_bucket = + bucket_entry::EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + serializer(empty_bucket); + } else { + const std::int16_t dist_from_ideal_bucket = + bucket.dist_from_ideal_bucket(); + serializer(dist_from_ideal_bucket); + if (STORE_HASH) { + const std::uint32_t truncated_hash = bucket.truncated_hash(); + serializer(truncated_hash); + } + serializer(bucket.value()); + } + } + } + + template + void deserialize_impl(Deserializer& deserializer, bool hash_compatible) { + tsl_rh_assert(m_buckets_data.empty()); // Current hash table must be empty + + const slz_size_type version = + deserialize_value(deserializer); + // For now we only have one version of the serialization protocol. + // If it doesn't match there is a problem with the file. + if (version != SERIALIZATION_PROTOCOL_VERSION) { + TSL_RH_THROW_OR_TERMINATE(std::runtime_error, + "Can't deserialize the ordered_map/set. " + "The protocol version header is invalid."); + } + + const bool hash_stored_for_bucket = + deserialize_value(deserializer) ? true : false; + if (hash_compatible && STORE_HASH != hash_stored_for_bucket) { + TSL_RH_THROW_OR_TERMINATE( + std::runtime_error, + "Can't deserialize a map with a different StoreHash " + "than the one used during the serialization when " + "hash compatibility is used"); + } + + const slz_size_type nb_elements = + deserialize_value(deserializer); + const slz_size_type bucket_count_ds = + deserialize_value(deserializer); + const float min_load_factor = deserialize_value(deserializer); + const float max_load_factor = deserialize_value(deserializer); + + if (min_load_factor < MINIMUM_MIN_LOAD_FACTOR || + min_load_factor > MAXIMUM_MIN_LOAD_FACTOR) { + TSL_RH_THROW_OR_TERMINATE( + std::runtime_error, + "Invalid min_load_factor. Check that the serializer " + "and deserializer support floats correctly as they " + "can be converted implicitly to ints."); + } + + if (max_load_factor < MINIMUM_MAX_LOAD_FACTOR || + max_load_factor > MAXIMUM_MAX_LOAD_FACTOR) { + TSL_RH_THROW_OR_TERMINATE( + std::runtime_error, + "Invalid max_load_factor. Check that the serializer " + "and deserializer support floats correctly as they " + "can be converted implicitly to ints."); + } + + this->min_load_factor(min_load_factor); + this->max_load_factor(max_load_factor); + + if (bucket_count_ds == 0) { + tsl_rh_assert(nb_elements == 0); + return; + } + + if (!hash_compatible) { + reserve(numeric_cast(nb_elements, + "Deserialized nb_elements is too big.")); + for (slz_size_type ibucket = 0; ibucket < bucket_count_ds; ibucket++) { + const distance_type dist_from_ideal_bucket = + deserialize_value(deserializer); + if (dist_from_ideal_bucket != + bucket_entry::EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET) { + if (hash_stored_for_bucket) { + TSL_RH_UNUSED(deserialize_value(deserializer)); + } + + insert(deserialize_value(deserializer)); + } + } + + tsl_rh_assert(nb_elements == size()); + } else { + m_bucket_count = numeric_cast( + bucket_count_ds, "Deserialized bucket_count is too big."); + + GrowthPolicy::operator=(GrowthPolicy(m_bucket_count)); + // GrowthPolicy should not modify the bucket count we got from + // deserialization + if (m_bucket_count != bucket_count_ds) { + TSL_RH_THROW_OR_TERMINATE(std::runtime_error, + "The GrowthPolicy is not the same even " + "though hash_compatible is true."); + } + + m_nb_elements = numeric_cast( + nb_elements, "Deserialized nb_elements is too big."); + m_buckets_data.resize(m_bucket_count); + m_buckets = m_buckets_data.data(); + + for (bucket_entry& bucket : m_buckets_data) { + const distance_type dist_from_ideal_bucket = + deserialize_value(deserializer); + if (dist_from_ideal_bucket != + bucket_entry::EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET) { + truncated_hash_type truncated_hash = 0; + if (hash_stored_for_bucket) { + tsl_rh_assert(hash_stored_for_bucket); + truncated_hash = deserialize_value(deserializer); + } + + bucket.set_value_of_empty_bucket( + dist_from_ideal_bucket, truncated_hash, + deserialize_value(deserializer)); + } + } + + if (!m_buckets_data.empty()) { + m_buckets_data.back().set_as_last_bucket(); + } + } + } + + public: + static const size_type DEFAULT_INIT_BUCKETS_SIZE = 0; + + static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.5f; + static constexpr float MINIMUM_MAX_LOAD_FACTOR = 0.2f; + static constexpr float MAXIMUM_MAX_LOAD_FACTOR = 0.95f; + + static constexpr float DEFAULT_MIN_LOAD_FACTOR = 0.0f; + static constexpr float MINIMUM_MIN_LOAD_FACTOR = 0.0f; + static constexpr float MAXIMUM_MIN_LOAD_FACTOR = 0.15f; + + static_assert(MINIMUM_MAX_LOAD_FACTOR < MAXIMUM_MAX_LOAD_FACTOR, + "MINIMUM_MAX_LOAD_FACTOR should be < MAXIMUM_MAX_LOAD_FACTOR"); + static_assert(MINIMUM_MIN_LOAD_FACTOR < MAXIMUM_MIN_LOAD_FACTOR, + "MINIMUM_MIN_LOAD_FACTOR should be < MAXIMUM_MIN_LOAD_FACTOR"); + static_assert(MAXIMUM_MIN_LOAD_FACTOR < MINIMUM_MAX_LOAD_FACTOR, + "MAXIMUM_MIN_LOAD_FACTOR should be < MINIMUM_MAX_LOAD_FACTOR"); + + private: + /** + * Protocol version currenlty used for serialization. + */ + static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1; + + /** + * Return an always valid pointer to an static empty bucket_entry with + * last_bucket() == true. + */ + bucket_entry* static_empty_bucket_ptr() noexcept { + static bucket_entry empty_bucket(true); + tsl_rh_assert(empty_bucket.empty()); + return &empty_bucket; + } + + private: + buckets_container_type m_buckets_data; + + /** + * Points to m_buckets_data.data() if !m_buckets_data.empty() otherwise points + * to static_empty_bucket_ptr. This variable is useful to avoid the cost of + * checking if m_buckets_data is empty when trying to find an element. + * + * TODO Remove m_buckets_data and only use a pointer instead of a + * pointer+vector to save some space in the robin_hash object. Manage the + * Allocator manually. + */ + bucket_entry* m_buckets; + + /** + * Used a lot in find, avoid the call to m_buckets_data.size() which is a bit + * slower. + */ + size_type m_bucket_count; + + size_type m_nb_elements; + + size_type m_load_threshold; + + float m_min_load_factor; + float m_max_load_factor; + + bool m_grow_on_next_insert; + + /** + * We can't shrink down the map on erase operations as the erase methods need + * to return the next iterator. Shrinking the map would invalidate all the + * iterators and we could not return the next iterator in a meaningful way, On + * erase, we thus just indicate on erase that we should try to shrink the hash + * table on the next insert if we go below the min_load_factor. + */ + bool m_try_shrink_on_next_insert; +}; + +} // namespace detail_robin_hash + +} // namespace tsl + +#endif diff --git a/3rdparty/robin-map/include/tsl/robin_map.h b/3rdparty/robin-map/include/tsl/robin_map.h new file mode 100644 index 00000000..aeb354c3 --- /dev/null +++ b/3rdparty/robin-map/include/tsl/robin_map.h @@ -0,0 +1,807 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_MAP_H +#define TSL_ROBIN_MAP_H + +#include +#include +#include +#include +#include +#include + +#include "robin_hash.h" + +namespace tsl { + +/** + * Implementation of a hash map using open-addressing and the robin hood hashing + * algorithm with backward shift deletion. + * + * For operations modifying the hash map (insert, erase, rehash, ...), the + * strong exception guarantee is only guaranteed when the expression + * `std::is_nothrow_swappable>::value && + * std::is_nothrow_move_constructible>::value` is true, + * otherwise if an exception is thrown during the swap or the move, the hash map + * may end up in a undefined state. Per the standard a `Key` or `T` with a + * noexcept copy constructor and no move constructor also satisfies the + * `std::is_nothrow_move_constructible>::value` criterion (and + * will thus guarantee the strong exception for the map). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the + * values. It can improve the performance during lookups if the `KeyEqual` + * function takes time (if it engenders a cache-miss for example) as we then + * compare the stored hashes before comparing the keys. When + * `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also + * speed-up the rehash process as we can avoid to recalculate the hash. When it + * is detected that storing the hash will not incur any memory penalty due to + * alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry) == sizeof(tsl::detail_robin_hash::bucket_entry)`) + * and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored + * even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the map grows and consequently how a hash value is + * mapped to a bucket. By default the map uses + * `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of + * buckets to a power of two and uses a mask to map the hash to a bucket instead + * of the slow modulo. Other growth policies are available and you may define + * your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the + * interface. + * + * `std::pair` must be swappable. + * + * `Key` and `T` must be copy and/or move constructible. + * + * If the destructor of `Key` or `T` throws an exception, the behaviour of the + * class is undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective + * insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_map { + private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()( + const std::pair& key_value) const noexcept { + return key_value.first; + } + + key_type& operator()(std::pair& key_value) noexcept { + return key_value.first; + } + }; + + class ValueSelect { + public: + using value_type = T; + + const value_type& operator()( + const std::pair& key_value) const noexcept { + return key_value.second; + } + + value_type& operator()(std::pair& key_value) noexcept { + return key_value.second; + } + }; + + using ht = detail_robin_hash::robin_hash, KeySelect, + ValueSelect, Hash, KeyEqual, + Allocator, StoreHash, GrowthPolicy>; + + public: + using key_type = typename ht::key_type; + using mapped_type = T; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + public: + /* + * Constructors + */ + robin_map() : robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {} + + explicit robin_map(size_type bucket_count, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : m_ht(bucket_count, hash, equal, alloc) {} + + robin_map(size_type bucket_count, const Allocator& alloc) + : robin_map(bucket_count, Hash(), KeyEqual(), alloc) {} + + robin_map(size_type bucket_count, const Hash& hash, const Allocator& alloc) + : robin_map(bucket_count, hash, KeyEqual(), alloc) {} + + explicit robin_map(const Allocator& alloc) + : robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {} + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : robin_map(bucket_count, hash, equal, alloc) { + insert(first, last); + } + + template + robin_map(InputIt first, InputIt last, size_type bucket_count, + const Allocator& alloc) + : robin_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) {} + + template + robin_map(InputIt first, InputIt last, size_type bucket_count, + const Hash& hash, const Allocator& alloc) + : robin_map(first, last, bucket_count, hash, KeyEqual(), alloc) {} + + robin_map(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : robin_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) {} + + robin_map(std::initializer_list init, size_type bucket_count, + const Allocator& alloc) + : robin_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), + alloc) {} + + robin_map(std::initializer_list init, size_type bucket_count, + const Hash& hash, const Allocator& alloc) + : robin_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), + alloc) {} + + robin_map& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + template ::value>::type* = nullptr> + std::pair insert(P&& value) { + return m_ht.emplace(std::forward

(value)); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + template ::value>::type* = nullptr> + iterator insert(const_iterator hint, P&& value) { + return m_ht.emplace_hint(hint, std::forward

(value)); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + template + std::pair insert_or_assign(const key_type& k, M&& obj) { + return m_ht.insert_or_assign(k, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& k, M&& obj) { + return m_ht.insert_or_assign(std::move(k), std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { + return m_ht.insert_or_assign(hint, k, std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { + return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); + } + + /** + * Due to the way elements are stored, emplace will need to move or copy the + * key-value once. The method is equivalent to + * insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy + * the key-value once. The method is equivalent to insert(hint, + * value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + template + std::pair try_emplace(const key_type& k, Args&&... args) { + return m_ht.try_emplace(k, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& k, Args&&... args) { + return m_ht.try_emplace(std::move(k), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, std::move(k), + std::forward(args)...); + } + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { + return m_ht.erase(first, last); + } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type erase(const K& key) { + return m_ht.erase(key); + } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup to the value if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + void swap(robin_map& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + T& at(const Key& key) { return m_ht.at(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + T& at(const Key& key, std::size_t precalculated_hash) { + return m_ht.at(key, precalculated_hash); + } + + const T& at(const Key& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const Key& key, std::size_t precalculated_hash) + */ + const T& at(const Key& key, std::size_t precalculated_hash) const { + return m_ht.at(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + T& at(const K& key) { + return m_ht.at(key); + } + + /** + * @copydoc at(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + T& at(const K& key, std::size_t precalculated_hash) { + return m_ht.at(key, precalculated_hash); + } + + /** + * @copydoc at(const K& key) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const T& at(const K& key) const { + return m_ht.at(key); + } + + /** + * @copydoc at(const K& key, std::size_t precalculated_hash) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const T& at(const K& key, std::size_t precalculated_hash) const { + return m_ht.at(key, precalculated_hash); + } + + T& operator[](const Key& key) { return m_ht[key]; } + T& operator[](Key&& key) { return m_ht[std::move(key)]; } + + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type count(const K& key) const { + return m_ht.count(key); + } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { + return m_ht.find(key, precalculated_hash); + } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + iterator find(const K& key) { + return m_ht.find(key); + } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { + return m_ht.find(key, precalculated_hash); + } + + /** + * @copydoc find(const K& key) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const_iterator find(const K& key) const { + return m_ht.find(key); + } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + bool contains(const Key& key) const { return m_ht.contains(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + bool contains(const Key& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + bool contains(const K& key) const { + return m_ht.contains(key); + } + + /** + * @copydoc contains(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + bool contains(const K& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) { + return m_ht.equal_range(key); + } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, + std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range( + const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key) { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key, + std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key) const { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range( + const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + + float min_load_factor() const { return m_ht.min_load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + + /** + * Set the `min_load_factor` to `ml`. When the `load_factor` of the map goes + * below `min_load_factor` after some erase operations, the map will be + * shrunk when an insertion occurs. The erase method itself never shrinks + * the map. + * + * The default value of `min_load_factor` is 0.0f, the map never shrinks by + * default. + */ + void min_load_factor(float ml) { m_ht.min_load_factor(ml); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count_) { m_ht.rehash(count_); } + void reserve(size_type count_) { m_ht.reserve(count_); } + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + /** + * Serialize the map through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the + * following call: + * - `template void operator()(const U& value);` where the types + * `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and + * `std::pair` must be supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for + * floats, ...) of the types it serializes in the hands of the `Serializer` + * function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized map through the `deserializer` + * parameter. + * + * The `deserializer` parameter must be a function object that supports the + * following call: + * - `template U operator()();` where the types `std::int16_t`, + * `std::uint32_t`, `std::uint64_t`, `float` and `std::pair` must be + * supported for U. + * + * If the deserialized hash map type is hash compatible with the serialized + * map, the deserialization process can be sped up by setting + * `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and + * GrowthPolicy must behave the same way than the ones used on the serialized + * map and the StoreHash must have the same value. The `std::size_t` must also + * be of the same size as the one on the platform used to serialize the map. + * If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` and `T` of the `robin_map` are + * not the same as the types used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for + * floats, size of int, ...) of the types it deserializes in the hands of the + * `Deserializer` function object if compatibility is required. + */ + template + static robin_map deserialize(Deserializer& deserializer, + bool hash_compatible = false) { + robin_map map(0); + map.m_ht.deserialize(deserializer, hash_compatible); + + return map; + } + + friend bool operator==(const robin_map& lhs, const robin_map& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + + for (const auto& element_lhs : lhs) { + const auto it_element_rhs = rhs.find(element_lhs.first); + if (it_element_rhs == rhs.cend() || + element_lhs.second != it_element_rhs->second) { + return false; + } + } + + return true; + } + + friend bool operator!=(const robin_map& lhs, const robin_map& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_map& lhs, robin_map& rhs) { lhs.swap(rhs); } + + private: + ht m_ht; +}; + +/** + * Same as `tsl::robin_map`. + */ +template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false> +using robin_pg_map = robin_map; + +} // end namespace tsl + +#endif diff --git a/3rdparty/robin-map/include/tsl/robin_set.h b/3rdparty/robin-map/include/tsl/robin_set.h new file mode 100644 index 00000000..54789509 --- /dev/null +++ b/3rdparty/robin-map/include/tsl/robin_set.h @@ -0,0 +1,660 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_SET_H +#define TSL_ROBIN_SET_H + +#include +#include +#include +#include +#include +#include + +#include "robin_hash.h" + +namespace tsl { + +/** + * Implementation of a hash set using open-addressing and the robin hood hashing + * algorithm with backward shift deletion. + * + * For operations modifying the hash set (insert, erase, rehash, ...), the + * strong exception guarantee is only guaranteed when the expression + * `std::is_nothrow_swappable::value && + * std::is_nothrow_move_constructible::value` is true, otherwise if an + * exception is thrown during the swap or the move, the hash set may end up in a + * undefined state. Per the standard a `Key` with a noexcept copy constructor + * and no move constructor also satisfies the + * `std::is_nothrow_move_constructible::value` criterion (and will thus + * guarantee the strong exception for the set). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the + * values. It can improve the performance during lookups if the `KeyEqual` + * function takes time (or engenders a cache-miss for example) as we then + * compare the stored hashes before comparing the keys. When + * `tsl::rh::power_of_two_growth_policy` is used as `GrowthPolicy`, it may also + * speed-up the rehash process as we can avoid to recalculate the hash. When it + * is detected that storing the hash will not incur any memory penalty due to + * alignment (i.e. `sizeof(tsl::detail_robin_hash::bucket_entry) == sizeof(tsl::detail_robin_hash::bucket_entry)`) + * and `tsl::rh::power_of_two_growth_policy` is used, the hash will be stored + * even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the set grows and consequently how a hash value is + * mapped to a bucket. By default the set uses + * `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of + * buckets to a power of two and uses a mask to set the hash to a bucket instead + * of the slow modulo. Other growth policies are available and you may define + * your own growth policy, check `tsl::rh::power_of_two_growth_policy` for the + * interface. + * + * `Key` must be swappable. + * + * `Key` must be copy and/or move constructible. + * + * If the destructor of `Key` throws an exception, the behaviour of the class is + * undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective + * insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator, bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_set { + private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const Key& key) const noexcept { return key; } + + key_type& operator()(Key& key) noexcept { return key; } + }; + + using ht = detail_robin_hash::robin_hash; + + public: + using key_type = typename ht::key_type; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + /* + * Constructors + */ + robin_set() : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {} + + explicit robin_set(size_type bucket_count, const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : m_ht(bucket_count, hash, equal, alloc) {} + + robin_set(size_type bucket_count, const Allocator& alloc) + : robin_set(bucket_count, Hash(), KeyEqual(), alloc) {} + + robin_set(size_type bucket_count, const Hash& hash, const Allocator& alloc) + : robin_set(bucket_count, hash, KeyEqual(), alloc) {} + + explicit robin_set(const Allocator& alloc) + : robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {} + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : robin_set(bucket_count, hash, equal, alloc) { + insert(first, last); + } + + template + robin_set(InputIt first, InputIt last, size_type bucket_count, + const Allocator& alloc) + : robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) {} + + template + robin_set(InputIt first, InputIt last, size_type bucket_count, + const Hash& hash, const Allocator& alloc) + : robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) {} + + robin_set(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()) + : robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) {} + + robin_set(std::initializer_list init, size_type bucket_count, + const Allocator& alloc) + : robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), + alloc) {} + + robin_set(std::initializer_list init, size_type bucket_count, + const Hash& hash, const Allocator& alloc) + : robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), + alloc) {} + + robin_set& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + /** + * Due to the way elements are stored, emplace will need to move or copy the + * key-value once. The method is equivalent to + * insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy + * the key-value once. The method is equivalent to insert(hint, + * value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { + return m_ht.erase(first, last); + } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type erase(const K& key) { + return m_ht.erase(key); + } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup to the value if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + void swap(robin_set& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type count(const K& key) const { + return m_ht.count(key); + } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { + return m_ht.find(key, precalculated_hash); + } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + iterator find(const K& key) { + return m_ht.find(key); + } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { + return m_ht.find(key, precalculated_hash); + } + + /** + * @copydoc find(const K& key) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const_iterator find(const K& key) const { + return m_ht.find(key); + } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + bool contains(const Key& key) const { return m_ht.contains(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + bool contains(const Key& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + bool contains(const K& key) const { + return m_ht.contains(key); + } + + /** + * @copydoc contains(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + bool contains(const K& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) { + return m_ht.equal_range(key); + } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, + std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range( + const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef + * KeyEqual::is_transparent exists. If so, K must be hashable and comparable + * to Key. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key) { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The + * hash value should be the same as hash_function()(key). Useful to speed-up + * the lookup if you already have the hash. + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key, + std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range(const K& key) const { + return m_ht.equal_range(key); + } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template < + class K, class KE = KeyEqual, + typename std::enable_if::value>::type* = nullptr> + std::pair equal_range( + const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + + float min_load_factor() const { return m_ht.min_load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + + /** + * Set the `min_load_factor` to `ml`. When the `load_factor` of the set goes + * below `min_load_factor` after some erase operations, the set will be + * shrunk when an insertion occurs. The erase method itself never shrinks + * the set. + * + * The default value of `min_load_factor` is 0.0f, the set never shrinks by + * default. + */ + void min_load_factor(float ml) { m_ht.min_load_factor(ml); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count_) { m_ht.rehash(count_); } + void reserve(size_type count_) { m_ht.reserve(count_); } + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + friend bool operator==(const robin_set& lhs, const robin_set& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + + for (const auto& element_lhs : lhs) { + const auto it_element_rhs = rhs.find(element_lhs); + if (it_element_rhs == rhs.cend()) { + return false; + } + } + + return true; + } + + /** + * Serialize the set through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the + * following call: + * - `template void operator()(const U& value);` where the types + * `std::int16_t`, `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be + * supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for + * floats, ...) of the types it serializes in the hands of the `Serializer` + * function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized set through the `deserializer` + * parameter. + * + * The `deserializer` parameter must be a function object that supports the + * following call: + * - `template U operator()();` where the types `std::int16_t`, + * `std::uint32_t`, `std::uint64_t`, `float` and `Key` must be supported for + * U. + * + * If the deserialized hash set type is hash compatible with the serialized + * set, the deserialization process can be sped up by setting + * `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and + * GrowthPolicy must behave the same way than the ones used on the serialized + * set and the StoreHash must have the same value. The `std::size_t` must also + * be of the same size as the one on the platform used to serialize the set. + * If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` of the `robin_set` is not the + * same as the type used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for + * floats, size of int, ...) of the types it deserializes in the hands of the + * `Deserializer` function object if compatibility is required. + */ + template + static robin_set deserialize(Deserializer& deserializer, + bool hash_compatible = false) { + robin_set set(0); + set.m_ht.deserialize(deserializer, hash_compatible); + + return set; + } + + friend bool operator!=(const robin_set& lhs, const robin_set& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_set& lhs, robin_set& rhs) { lhs.swap(rhs); } + + private: + ht m_ht; +}; + +/** + * Same as `tsl::robin_set`. + */ +template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator, bool StoreHash = false> +using robin_pg_set = robin_set; + +} // end namespace tsl + +#endif diff --git a/3rdparty/robin-map/tsl-robin-map.natvis b/3rdparty/robin-map/tsl-robin-map.natvis new file mode 100644 index 00000000..f6eb842e --- /dev/null +++ b/3rdparty/robin-map/tsl-robin-map.natvis @@ -0,0 +1,78 @@ + + + + + + + + {{ size={m_ht.m_nb_elements} }} + + m_ht.m_buckets_data._Mypair._Myval2._Mylast - m_ht.m_buckets_data._Mypair._Myval2._Myfirst + + ((float)m_ht.m_nb_elements) / ((float)(m_ht.m_buckets_data._Mypair._Myval2._Mylast - m_ht.m_buckets_data._Mypair._Myval2._Myfirst)) + + + 0 + + m_ht.m_max_load_factor + + + + m_ht.m_nb_elements + + *bucket + + ++bucket + + + + + + + + {{ size={m_ht.m_nb_elements} }} + + m_ht.m_buckets_data._Mypair._Myval2._Mylast - m_ht.m_buckets_data._Mypair._Myval2._Myfirst + + ((float)m_ht.m_nb_elements) / ((float)(m_ht.m_buckets_data._Mypair._Myval2._Mylast - m_ht.m_buckets_data._Mypair._Myval2._Myfirst)) + + + 0 + + m_ht.m_max_load_factor + + + + m_ht.m_nb_elements + + *bucket + + ++bucket + + + + + + + {*m_bucket} + + *m_bucket + + + + + empty + {*reinterpret_cast<$T1*>(&m_value)} + + *reinterpret_cast<$T1*>(&m_value) + + + + + empty + {reinterpret_cast<$T1*>(&m_value)->second} + + *reinterpret_cast<$T1*>(&m_value) + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 31101b59..c2f4ca2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ if (CMAKE_VERSION VERSION_LESS "2.8.12") cmake_minimum_required(VERSION 2.8.9) set(HEAPTRACK_BUILD_GUI OFF) -else() +elseif (CMAKE_VERSION VERSION_LESS "3.16.0") cmake_minimum_required(VERSION 2.8.12) +else() + cmake_minimum_required(VERSION 3.16.0) endif() project(heaptrack) @@ -14,23 +16,42 @@ if(NOT CMAKE_BUILD_TYPE) endif() set(HEAPTRACK_VERSION_MAJOR 1) -set(HEAPTRACK_VERSION_MINOR 2) +set(HEAPTRACK_VERSION_MINOR 5) set(HEAPTRACK_VERSION_PATCH 80) -set(HEAPTRACK_LIB_VERSION 1.2.80) +set(HEAPTRACK_LIB_VERSION 1.5.80) set(HEAPTRACK_LIB_SOVERSION 2) -set(HEAPTRACK_FILE_FORMAT_VERSION 2) +set(HEAPTRACK_FILE_FORMAT_VERSION 3) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +option(APPIMAGE_BUILD "configure build for bundling in an appimage" OFF) + +set(REQUIRED_IN_APPIMAGE "") +if (APPIMAGE_BUILD) + set(REQUIRED_IN_APPIMAGE REQUIRED) +endif() + include(FeatureSummary) -find_package(Boost 1.41.0 COMPONENTS system filesystem iostreams) +find_package(Boost 1.60.0 ${REQUIRED_IN_APPIMAGE} COMPONENTS system filesystem iostreams container) +set_package_properties(Boost PROPERTIES TYPE RECOMMENDED PURPOSE "Boost container libraries can greatly improve performance (via pmr allocators)") find_package(Threads REQUIRED) find_package(ZLIB REQUIRED) if (${Boost_IOSTREAMS_FOUND}) - find_package(Zstd) + find_package(ZSTD ${REQUIRED_IN_APPIMAGE}) + + include(CheckCXXSourceCompiles) + include(CMakePushCheckState) + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${Boost_LIBRARIES}) + check_cxx_source_compiles("#include + int main() { boost::iostreams::zstd_decompressor(); return 0; }" + BOOST_IOSTREAMS_HAS_ZSTD + ) + cmake_pop_check_state() endif() -set_package_properties(Zstd PROPERTIES TYPE RECOMMENDED PURPOSE "Zstandard offers better (de)compression performance compared with gzip/zlib, making heaptrack faster and datafiles smaller.") +set_package_properties(ZSTD PROPERTIES TYPE RECOMMENDED PURPOSE "Zstandard offers better (de)compression performance compared with gzip/zlib, making heaptrack faster and datafiles smaller.") if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(HEAPTRACK_BUILD_TRACK_DEFAULT ON) @@ -46,22 +67,12 @@ option( ${HEAPTRACK_BUILD_TRACK_DEFAULT} ) -option( - HEAPTRACK_BUILD_BACKTRACE - "Enable this option to build libbacktrace. It will be enabled implicitly if HEAPTRACK_BUILD_INTERPRET is enabled." - OFF -) - option( HEAPTRACK_BUILD_INTERPRET "Disable this option to skip building the interpret part for heaptrack." ${HEAPTRACK_BUILD_INTERPRET_DEFAULT} ) -if (HEAPTRACK_BUILD_INTERPRET) - set(HEAPTRACK_BUILD_BACKTRACE ON) -endif() - if (CMAKE_CROSSCOMPILING) set(HEAPTRACK_BUILD_ANALYZE_DEFAULT OFF) else() @@ -76,10 +87,24 @@ option( option( HEAPTRACK_BUILD_GUI - "Disable this option to skip building the Qt5 / KF5 based GUI for heaptrack." + "Disable this option to skip building the Qt / KDE Frameworks based GUI for heaptrack." ${HEAPTRACK_BUILD_ANALYZE_DEFAULT} ) +option( + HEAPTRACK_USE_QT6 + "Use Qt6/KF6 when building the Qt / KDE Frameworks based GUI for heaptrack." + OFF +) +if(HEAPTRACK_USE_QT6) + set(QT_VERSION_MAJOR 6) + # possibly works with older Qt6, but I didn't test that yet + set(QT_MIN_VERSION 6.5.0) +else() + set(QT_VERSION_MAJOR 5) + set(QT_MIN_VERSION 5.10.0) +endif() + option( HEAPTRACK_USE_LIBUNWIND "Define preferred unwind functionality - Libunwind as ON and unwind_tables as OFF." @@ -89,21 +114,13 @@ option( set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) if (NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror=undef -Werror=return-type") endif() -include (CheckCXXSourceCompiles) -check_cxx_source_compiles( - "#include - #include - thread_local int tls; - int main() { return 0; }" - HAVE_CXX11_SUPPORT) - -if (NOT HAVE_CXX11_SUPPORT) - message(FATAL_ERROR "Your compiler is too old and does not support the required C++11 features.") -endif() +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +include (CheckCXXSourceCompiles) # cfree() does not exist in glibc 2.26+. # See: https://bugs.kde.org/show_bug.cgi?id=383889 @@ -126,6 +143,13 @@ file(RELATIVE_PATH LIB_REL_PATH set(ECM_ENABLE_SANITIZERS "" CACHE STRING "semicolon-separated list of sanitizers to enable for code that is not injected into client applications") +if (ECM_ENABLE_SANITIZERS) + find_package(ECM 1.0.0 NO_MODULE) + if (ECM_FOUND) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + endif() +endif() + if (HEAPTRACK_BUILD_TRACK) if (HEAPTRACK_USE_LIBUNWIND) find_package(Libunwind REQUIRED) @@ -150,4 +174,8 @@ add_subdirectory(3rdparty) add_subdirectory(src) add_subdirectory(tests) +# Let releaseme know about this: +# SKIP_PO_INSTALL +# (KF5I18n is optional in src/analyze/CMakeLists.txt...) + feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/COPYING b/COPYING deleted file mode 100644 index 4362b491..00000000 --- a/COPYING +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 00000000..137069b8 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 00000000..6c9eef8d --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/BSL-1.0.txt b/LICENSES/BSL-1.0.txt new file mode 100644 index 00000000..2d87ab1a --- /dev/null +++ b/LICENSES/BSL-1.0.txt @@ -0,0 +1,7 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSES/GPL-2.0-or-later.txt b/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 00000000..17cb2864 --- /dev/null +++ b/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,117 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. + + c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. + +signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice diff --git a/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt new file mode 100644 index 00000000..c9aa5301 --- /dev/null +++ b/LICENSES/LGPL-2.1-only.txt @@ -0,0 +1,175 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. + + e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/LGPL-2.1-or-later.txt b/LICENSES/LGPL-2.1-or-later.txt new file mode 100644 index 00000000..aaaba168 --- /dev/null +++ b/LICENSES/LGPL-2.1-or-later.txt @@ -0,0 +1,462 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the version +number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software Foundation +and other authors who decide to use it. You can use it too, but we suggest +you first think carefully about whether this license or the ordinary General +Public License is the better strategy to use in any particular case, based +on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. +Our General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish); that you receive source code or can get it if you want it; that you +can change the software and use pieces of it in new free programs; and that +you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors +to deny you these rights or to ask you to surrender these rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +other code with the library, you must provide complete object files to the +recipients, so that they can relink them with the library after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, +and (2) we offer you this license, which gives you legal permission to copy, +distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free +program. We wish to make sure that a company cannot effectively restrict the +users of a free program by obtaining a restrictive license from a patent holder. +Therefore, we insist that any patent license obtained for a version of the +library must be consistent with the full freedom of use specified in this +license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public License, +applies to certain designated libraries, and is quite different from the ordinary +General Public License. We use this license for certain libraries in order +to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared +library, the combination of the two is legally speaking a combined work, a +derivative of the original library. The ordinary General Public License therefore +permits such linking only if the entire combination fits its criteria of freedom. +The Lesser General Public License permits more lax criteria for linking other +code with the library. + +We call this license the "Lesser" General Public License because it does Less +to protect the user's freedom than the ordinary General Public License. It +also provides other free software developers Less of an advantage over competing +non-free programs. These disadvantages are the reason we use the ordinary +General Public License for many libraries. However, the Lesser license provides +advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the +widest possible use of a certain library, so that it becomes a de-facto standard. +To achieve this, non-free programs must be allowed to use the library. A more +frequent case is that a free library does the same job as widely used non-free +libraries. In this case, there is little to gain by limiting the free library +to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free software. For +example, permission to use the GNU C Library in non-free programs enables +many more people to use the whole GNU operating system, as well as its variant, +the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a modified +version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, whereas the latter must be combined with the library in +order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program +which contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Lesser General +Public License (also called "this License"). Each licensee is addressed as +"you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (1) uses at run time a copy of the library +already present on the user's computer system, rather than copying library +functions into the executable, and (2) will operate properly with a modified +version of the library, if the user installs one, as long as the modified +version is interface-compatible with the version that the work was made with. + +c) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +d) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +e) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the materials to be distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Lesser General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information +on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 00000000..2071b23b --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 4f6fb0e8..ccf582a0 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Both parts require the following tools and libraries: - a C\+\+11 enabled compiler like g\+\+ or clang\+\+ - zlib - optionally: zstd for faster (de)compression +- elfutils - libdl - pthread - libc @@ -77,7 +78,6 @@ following libraries: - boost 1.41 or higher: iostreams, program_options - libunwind -- elfutils: libdwarf For runtime-attaching, you will need `gdb` installed. @@ -88,7 +88,7 @@ depends on Qt 5 and some KDE libraries: - extra-cmake-modules - Qt 5.2 or higher: Core, Widgets -- KDE Frameworks 5: CoreAddons, I18n, ItemModels, ThreadWeaver, ConfigWidgets, KIO +- KDE Frameworks 5: CoreAddons, I18n, ItemModels, ThreadWeaver, ConfigWidgets, KIO, IconThemes When any of these dependencies is missing, `heaptrack_gui` will not be build. Optionally, install the following dependencies to get additional features in @@ -112,14 +112,16 @@ of the CMake command, as it will tell you about missing dependencies! `heaptrack_print` and `heaptrack_gui` can be built on platforms other than Linux, using the dependencies mentioned above. On macOS the dependencies can be installed easily using [homebrew](http://brew.sh) and the [KDE homebrew tap](https://github.com/KDE-mac/homebrew-kde). + brew install qt@5 + # prepare tap - brew tap kde-mac/kde - "$(brew --repo)/Library/Taps/kde-mac/homebrew-kde/tools/all-fixes.sh" + brew tap kde-mac/kde https://invent.kde.org/packaging/homebrew-kde.git + "$(brew --repo kde-mac/kde)/tools/do-caveats.sh" # install dependencies - brew install kde-mac/kde/kf5-extra-cmake-modules kde-mac/kde/kf5-kcoreaddons kde-mac/kde/kf5-ki18n \ - kde-mac/kde/kf5-kitemmodels kde-mac/kde/kf5-threadweaver kde-mac/kde/kf5-kconfigwidgets \ + brew install kde-mac/kde/kf5-kcoreaddons kde-mac/kde/kf5-kitemmodels kde-mac/kde/kf5-kconfigwidgets \ kde-mac/kde/kf5-kio kde-mac/kde/kdiagram \ + extra-cmake-modules ki18n threadweaver \ boost zstd gettext # run manual steps as printed by brew @@ -133,7 +135,7 @@ To compile make sure to use Qt from homebrew and to have gettext in the path: cd heaptrack # i.e. the source folder mkdir build cd build - CMAKE_PREFIX_PATH=/usr/local/opt/qt PATH=$PATH:/usr/local/opt/gettext/bin cmake .. + CMAKE_PREFIX_PATH=/opt/homebrew/opt/qt@5 PATH=$PATH:/opt/homebrew/opt/gettext/bin cmake .. cmake -DCMAKE_BUILD_TYPE=Release .. # look for messages about missing dependencies! make heaptrack_gui heaptrack_print @@ -220,7 +222,7 @@ needed for a simple heap profiler. As a FOSS project, we welcome contributions of any form. You can help improve the project by: - submitting bug reports at https://bugs.kde.org/enter_bug.cgi?product=Heaptrack -- contributing patches via https://phabricator.kde.org/dashboard/view/28/ +- contributing patches via https://invent.kde.org/sdk/heaptrack - translating the GUI with the help of https://l10n.kde.org/ - writing documentation on https://userbase.kde.org/Heaptrack @@ -240,3 +242,14 @@ will see garbage backtraces that are completely broken. If you encounter such issues, try to relink your application and also libunwind with `ld.bfd` instead of `ld.gold`. You can see if you are affected by running the libunwind unit tests via `make check`. But do note that you need to relink your application too, not only libunwind. + +### Executables built with ASAN (Address Sanitizer) + +If you run heaptrack on an application built with ASAN, you'll likely get this fatal error on startup: + + ASan runtime does not come first in initial library list [...] + +The solution is to pass the `--asan` flag to heaptrack. +Note: this only work for binaries built with `gcc` (i.e. those which link to `libasan.so`). +Binaries built with `clang`'s ASAN enabled are not supported at the moment. + diff --git a/cmake/FindElfutils.cmake b/cmake/FindElfutils.cmake new file mode 100644 index 00000000..3e82df50 --- /dev/null +++ b/cmake/FindElfutils.cmake @@ -0,0 +1,55 @@ +# - Try to find libdw +# Once done this will define +# +# LIBDW_FOUND - system has libdwarf +# LIBDW_INCLUDE_DIRS - the libdwarf include directory +# LIBDW_LIBRARIES - Link these to use libdwarf +# LIBDW_DEFINITIONS - Compiler switches required for using libdwarf +# + +if (LIBDW_LIBRARIES AND LIBDW_INCLUDE_DIRS) + set (Elfutils_FIND_QUIETLY TRUE) +endif (LIBDW_LIBRARIES AND LIBDW_INCLUDE_DIRS) + +find_path (DWARF_INCLUDE_DIR + NAMES + dwarf.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ENV CPATH) # PATH and INCLUDE will also work +find_path (LIBDW_INCLUDE_DIR + NAMES + elfutils/libdw.h elfutils/libdwfl.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ENV CPATH) +if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR) + set (LIBDW_INCLUDE_DIRS ${DWARF_INCLUDE_DIR} ${LIBDW_INCLUDE_DIR}) +endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR) + +find_library (LIBDW_LIBRARIES + NAMES + dw + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ENV LIBRARY_PATH # PATH and LIB will also work + ENV LD_LIBRARY_PATH) + +include (FindPackageHandleStandardArgs) + +# handle the QUIETLY and REQUIRED arguments and set LIBDW_FOUND to TRUE +# if all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Elfutils DEFAULT_MSG + LIBDW_LIBRARIES + LIBDW_INCLUDE_DIR) + +mark_as_advanced(LIBDW_INCLUDE_DIR LIBDW_LIBRARIES) diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake index da808fb0..2dddfad9 100644 --- a/cmake/FindLibunwind.cmake +++ b/cmake/FindLibunwind.cmake @@ -1,10 +1,10 @@ #.rst: -# FindLibUnwind +# FindLibunwind # ----------- # -# Find LibUnwind +# Find Libunwind # -# Find LibUnwind headers and library +# Find Libunwind headers and library # # :: # @@ -18,17 +18,8 @@ # LIBUNWIND_VERSION_STRING - version number as a string (ex: "5.0.3") #============================================================================= -# Copyright 2014 ZBackup contributors -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) +# SPDX-FileCopyrightText: 2014 ZBackup contributors +# SPDX-License-Identifier: BSD-3-Clause find_path(LIBUNWIND_INCLUDE_DIR libunwind.h ) @@ -57,7 +48,7 @@ endif() if (LIBUNWIND_LIBRARY) include(CheckCSourceCompiles) set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) - set(CMAKE_REQUIRED_QUIET ${LibUnwind_FIND_QUIETLY}) + set(CMAKE_REQUIRED_QUIET ${Libunwind_FIND_QUIETLY}) set(CMAKE_REQUIRED_LIBRARIES_SAVE ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${LIBUNWIND_LIBRARY}) set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES}) @@ -69,13 +60,14 @@ if (LIBUNWIND_LIBRARY) check_c_source_compiles("#define UNW_LOCAL_ONLY 1\n#include \nint main() { void* buf[10]; unw_backtrace(&buf, 10); return 0; }" LIBUNWIND_HAS_UNW_BACKTRACE) check_c_source_compiles ("#define UNW_LOCAL_ONLY 1\n#include \nint main() { void* buf[10]; unw_backtrace_skip(&buf, 10, 2); return 0; }" LIBUNWIND_HAS_UNW_BACKTRACE_SKIP) check_c_source_compiles ("#define UNW_LOCAL_ONLY 1\n#include \nint main() { return unw_set_cache_size(unw_local_addr_space, 1024, 0); }" LIBUNWIND_HAS_UNW_SET_CACHE_SIZE) + check_c_source_compiles ("#define UNW_LOCAL_ONLY 1\n#include \nint main() { return unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD); }" LIBUNWIND_HAS_UNW_CACHE_PER_THREAD) set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE}) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE}) endif () include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUnwind REQUIRED_VARS LIBUNWIND_INCLUDE_DIR +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Libunwind REQUIRED_VARS LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARY LIBUNWIND_HAS_UNW_BACKTRACE VERSION_VAR LIBUNWIND_VERSION_STRING diff --git a/cmake/FindZstd.cmake b/cmake/FindZSTD.cmake similarity index 81% rename from cmake/FindZstd.cmake rename to cmake/FindZSTD.cmake index e50a95ab..d821e462 100644 --- a/cmake/FindZstd.cmake +++ b/cmake/FindZSTD.cmake @@ -1,5 +1,6 @@ # taken from: https://github.com/facebook/folly/blob/master/CMake/FindZstd.cmake -# should be apache 2.0, cf.: https://github.com/facebook/folly/blob/master/LICENSE +# SPDX-FileCopyrightText: Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 # # - Try to find Facebook zstd library # This will define diff --git a/logo.png b/logo.png new file mode 100644 index 00000000..7183198f Binary files /dev/null and b/logo.png differ diff --git a/po/ca/heaptrack.po b/po/ca/heaptrack.po new file mode 100644 index 00000000..1de84aa3 --- /dev/null +++ b/po/ca/heaptrack.po @@ -0,0 +1,1367 @@ +# Translation of heaptrack.po to Catalan +# Copyright (C) 2015-2023 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep M. Ferrer , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023. +# Antoni Bella Pérez , 2015, 2016, 2017, 2020, 2021. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-05-30 11:03+0200\n" +"Last-Translator: Josep M. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Generator: Lokalize 20.12.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep M. Ferrer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Ubicació" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Assignacions (Pròpies)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporals (Pròpies)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pics (Propis)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Perduts (Propis)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Assignacions (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporals (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pics (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Perduts (Incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"El símbol pare que ha cridat una funció d'assignació. Pot ser no resolta " +"si manca la informació de depuració." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"El nombre de vegades que una funció d'assignació s'ha cridat directament " +"des d'aquesta ubicació." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals directes. Aquestes assignacions són " +"seguides de forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"La memòria en monticles màxima en bytes consumida de les assignacions " +"originades directament en aquesta ubicació. Això té en compte les " +"desassignacions." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Els bytes assignats directament en aquesta ubicació que no s'han " +"desassignat." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"El nombre inclusiu de vegades que una funció d'assignació s'ha cridat " +"des d'aquesta ubicació." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals inclusives. Aquestes assignacions són " +"seguides de forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"La memòria en monticles màxima inclusiva en bytes consumida de les " +"assignacions originades en aquesta ubicació. Això té en compte les " +"desassignacions." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Els bytes assignats en aquesta ubicació que no s'han desassignat." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Cridador" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Cridat" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pic" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Perduts" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Assignacions" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporals" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"La ubicació de la %1. La funció d'assignació pot ser no resolta si manca la " +"informació de depuració." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"La ubicació del codi font que ha cridat una funció d'assignació. Pot ser " +"desconeguda si manca la informació de depuració." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Assignacions de memòria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memòria consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Assignacions temporals" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Temps transcorregut" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Assignacions de memòria en total" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Consum total de la memòria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Assignacions temporals en total" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 assignacions en total després de %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 assignacions temporals en total després de %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumits en total després de %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 assignacions després de %3 des de:

%1" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 assignacions temporals després de %3 des de:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" +"%2 consumits després de %3 des de:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exporta com a..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostra la llegenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostra la gràfica del cost total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostra la gràfica del cost detallat" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagrames apilats:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtre en la selecció" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reinicia el filtratge" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Desa %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Imatge ràster (*.png *.jpg *.tiff);;Imatge vectorial (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Ha fallat en desar la imatge a %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "IniciFinalDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Hora%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consum%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Assignacions%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Assignacions temporals%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Mostra el consum de memòria en monticles al llarg del temps.
Feu clic " +"i arrossegueu per a seleccionar un interval de temps per al filtratge.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra el nombre d'assignacions de memòria al llarg del temps.
Feu " +"clic i arrossegueu per a seleccionar un interval de temps per al filtratge." + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra el nombre d'assignacions temporals de memòria al llarg del temps. " +"Una assignació temporal és aquella que segueix immediatament la seva " +"desassignació corresponent, sense cap altra assignació entremig.
Feu clic " +"i arrossegueu per a seleccionar un interval de temps per al filtratge.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrat des de %2 a %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta filtrada)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Feu clic i arrossegueu per a seleccionar un interval de temps per al " +"filtratge." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consum: %2. Feu clic i arrossegueu per a seleccionar un interval de " +"temps per al filtratge." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Assignacions: %2. Feu clic i arrossegueu per a seleccionar un " +"interval de temps per al filtratge." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Assignacions temporals: %2. Feu clic i arrossegueu per a seleccionar " +"un interval de temps per al filtratge." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 assignacions en total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 assignacions temporals en total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 pics de consum de memòria" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 perduts en total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) assignacions a %3 i a sota." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) assignacions temporals a %3 i a sota." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contribució al pic de consum a %3 i a sota." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) perduts a %3 i a sota." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pic de memòria" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostra un gràfic de flames sobre les contribucions al pic de consum de " +"memòria en monticles de l'aplicació." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostra un gràfic de flames sobre la memòria en monticles perduda de " +"l'aplicació. Es considera que la memòria es perd quan no es desassigna mai." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostra un gràfic de flames sobre el nombre d'assignacions desencadenades per " +"funcions en el codi." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostra un gràfic de flames sobre el nombre d'assignacions temporals " +"desencadenades per funcions en el codi. Les assignacions es marquen com a " +"temporals quan estan seguides immediatament per la seva desassignació." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Seleccioneu l'origen de dades que s'ha de visualitzar en el gràfic de flames." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista de baix cap a dalt" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Activa la vista de baix cap a dalt del gràfic de flames. Quan això no està " +"activat, per defecte està activada la vista de dalt cap a baix." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Redueix la recursivitat" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Redueix els marcs de la pila per a les funcions que es criden a si mateixes. " +"Quan això no està activat, els marcs amb recursivitat es visualitzaran per " +"separat." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Llindar del cost: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"El llindar del cost defineix un valor fraccional de retall. Els elements " +"amb un cost relatiu inferior a aquest valor no es mostraran en el gràfic de " +"flames. Això es fa com una optimització per a generar ràpidament gràfics per " +"a conjunts de dades grans amb una sobrecàrrega de memòria baixa. Si calen " +"més detalls, reduïu el valor del llindar o definiu-lo a zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Cerca..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Carca un símbol al gràfic de flames." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Restaura la vista" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Vista del Cridador / Cridat" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "s'està generant el gràfic de flames..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% d'un total de %3) assignacions coincideixen a la cerca." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% d'un total de %3) coincideixen a la cerca." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "IGU del Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un visualitzador pels fitxers de dades del «heaptrack»." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor original, mantenidor" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Dades d'anàlisi de rendiment base a comparar amb altres fitxers." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Carrega la llista de supressions de fuites des del fitxer especificat. " +"Especifiqueu una supressió per línia i comenceu cada línia amb «leak:», és a " +"dir, useu el format de fitxer per a la supressió LSAN." + +# skip-rule: t-apo1,rst-link0italic,rst-italic2 +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignora les definicions de supressió que estan incrustades en el fitxer de " +"dades del Heaptrack. De manera predeterminada, el Heaptrack copiarà les " +"supressions definides de manera opcional mitjançant un símbol «const char " +"*__lsan_default_suppressions()» a l'aplicació de depuració. Aquestes " +"s'aplicaran sempre en analitzar les dades, llevat que s'inhabiliti " +"explícitament aquesta característica mitjançant aquesta opció de la línia " +"d'ordres." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignora les definicions de supressió que estan integrades en el Heaptrack. De " +"manera predeterminada, el Heaptrack suprimirà certes pèrdues conegudes en " +"les biblioteques habituals del de sistema." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Fitxers a carregar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FITXER...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 assignacions de %2, amb un total de %3 assignades amb una mitjana de %4 " +"per assignació" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Mida de l'assignació requerida" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Nombre d'assignacions" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Obre el fitxer a l'editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depuració:
%1 " +"(annexat)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depuració:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
temps total d'execució:
%1, filtrat des de %2 a %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
temps total d'execució:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memòria total del sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
crides a funcions d'assignació:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
assignacions temporals:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
pic de consum de memòria en monticles:
%1 després %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
pic RSS (incloent-hi la sobrecàrrega del «heaptrack»):
" +"%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta de consum de memòria en monticles:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
memòria total perduda:
%1 (%2 suprimida)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
memòria total perduda:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Ha fallat en analitzar el fitxer %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumida" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Mides" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "La dada d'entrada %1 no existeix." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "La dada d'entrada %1 no és cap fitxer." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "La dada d'entrada %1 no es pot llegir." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Ha fallat en analitzar la supressió del fitxer." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Inhabilita les supressions incrustades" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Inhabilita les supressions integrades" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignora les definicions de supressió que estan integrades en el Heaptrack. De " +"manera predeterminada, el Heaptrack suprimirà certes pèrdues conegudes de " +"les biblioteques habituals del de sistema." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "S'està carregant el fitxer %1. Si us plau, espereu..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 comparat amb %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "S'està tornant a analitzar el fitxer. Espereu..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegació pel codi" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalitzada..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automàtic (Sense nombre de línies)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegació personalitzada pel codi" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Especifiqueu l'ordre a usar per a la navegació pel codi, «%f» se substituirà " +"pel nom de fitxer, «%l» pel número de línia i «%c» pel número de columna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Finestra principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Camí cap a un fitxer que conté les regles per a la supressió de fuites en el " +"format LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Obre les dades del Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Aquest camp especifica el fitxer de dades primàries de «heaptrack». " +"Aquests fitxers s'anomenen heaptrack.$APP.$PID.gz o heaptrack." +"$APP.$PID.zst. Podeu crear aquests fitxers amb l'anàlisi del rendiment " +"de l'aplicació, p. ex. via:

\n" +"
heaptrack <aplicació> ...
\n" +"

O, alternativament, podeu annexar un procés en execució via

\n" +"
heaptrack --pid $(pidof <aplicació>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "camí/a/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Opcionalment, podeu especificar un segon fitxer de dades «heaptrack» per " +"a comparar-lo. Si es defineix, aquest fitxer s'utilitzarà com a base i el " +"seu cost es restarà dels costos de dades primaris." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dades d'anàlisi del rendiment:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Compara amb:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supressions:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "camí/a/supressions_lsan.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resum" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Llista de funcions que assignen la majoria de la memòria en un moment donat." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contribucions al pic" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Llista de funcions que perden la majoria de la memòria." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Pèrdues més grans de memòria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Llista de funcions que assignen la memòria més sovint." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Assignacions de memòria més freqüents" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Llista de funcions que produeixen la majoria de les assignacions temporals " +"de memòria." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Assignacions temporals més freqüents" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supressions" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "De baix a dalt" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtra per funció..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtra per fitxer..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtra per mòdul..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Cridador / Cridat" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "De dalt a baix" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Gràfic de flames" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Piles" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Pila seleccionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Fitxer" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Co&nfiguració" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtre" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "s'estan fusionant les assignacions... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "més que 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "s'està tornant a analitzar les dades" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "s'estan analitzant les dades" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 aprovat: %2/%3 gastat: %4 resta: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "s'estan fusionant les assignacions..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "s'està construint l'histograma..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "s'estan construint les taules..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Traça inversa" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"El nombre de vegades que una funció d'assignació s'ha cridat des " +"d'aquesta ubicació." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals. Aquestes assignacions són seguides " +"de forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Les contribucions des d'una ubicació donada al consum en bytes de la " +"memòria en monticles màxima. Això té en compte les desassignacions." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"La ubicació des de la qual s'ha cridat una funció d'assignació. El " +"símbol de la funció i la informació del fitxer poden ser desconeguts si " +"manca la informació de depuració quan es va executar el «heaptrack»." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" a %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contribució al pic: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "perduts: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "assignacions: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporals: %1 (%2% de les assignacions, %3% del total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Traça inversa:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "cridat des d'una ubicació" +msgstr[1] "cridat des de %1 ubicacions" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% d'un total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (propi): %2
  %4% d'un total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusiu): %2
  %4% d'un total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbol: %1
binari: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 a %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" diff --git a/po/ca@valencia/heaptrack.po b/po/ca@valencia/heaptrack.po new file mode 100644 index 00000000..cf2a4f04 --- /dev/null +++ b/po/ca@valencia/heaptrack.po @@ -0,0 +1,1366 @@ +# Translation of heaptrack.po to Catalan (Valencian) +# Copyright (C) 2015-2023 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep M. Ferrer , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023. +# Antoni Bella Pérez , 2015, 2016, 2017, 2020, 2021. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-05-30 11:03+0200\n" +"Last-Translator: Josep M. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Generator: Lokalize 20.12.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep M. Ferrer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Ubicació" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Assignacions (Pròpies)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporals (Pròpies)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pics (Propis)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Perduts (Propis)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Assignacions (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporals (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pics (Incl.)" + +# skip-rule: t-pu_desp +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Perduts (Incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"El símbol pare que ha cridat una funció d'assignació. Pot ser no resolta " +"si falta la informació de depuració." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"El nombre de vegades que una funció d'assignació s'ha cridat directament " +"des d'esta ubicació." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals directes. Estes assignacions són " +"seguides de forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"La memòria en monticles màxima en bytes consumida de les assignacions " +"originades directament en esta ubicació. Açò té en compte les " +"desassignacions." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Els bytes assignats directament en esta ubicació que no s'han " +"desassignat." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"El nombre inclusiu de vegades que una funció d'assignació s'ha cridat " +"des d'esta ubicació." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals inclusives. Estes assignacions són " +"seguides de forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"La memòria en monticles màxima inclusiva en bytes consumida de les " +"assignacions originades en esta ubicació. Açò té en compte les " +"desassignacions." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Els bytes assignats en esta ubicació que no s'han desassignat." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Cridador" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Cridat" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pic" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Perduts" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Assignacions" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporals" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"La ubicació de la %1. La funció d'assignació pot ser no resolta si falta la " +"informació de depuració." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"La ubicació del codi font que ha cridat una funció d'assignació. Pot ser " +"desconeguda si falta la informació de depuració." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Assignacions de memòria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memòria consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Assignacions temporals" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Temps transcorregut" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Assignacions de memòria en total" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Consum total de la memòria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Assignacions temporals en total" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 assignacions en total després de %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 assignacions temporals en total després de %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumits en total després de %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 assignacions després de %3 des de:

%1" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 assignacions temporals després de %3 des de:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" +"%2 consumits després de %3 des de:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exporta com a..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostra la llegenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostra la gràfica del cost total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostra la gràfica del cost detallat" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagrames apilats:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtre en la selecció" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reinicia el filtratge" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Guarda %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Imatge ràster (*.png *.jpg *.tiff);;Imatge vectorial (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "No s'ha pogut guardar la imatge a %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "IniciFinalDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Hora%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consum%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Assignacions%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Assignacions temporals%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Mostra el consum de memòria en monticles al llarg del temps.
Feu clic " +"i arrossegueu per a seleccionar un interval de temps per al filtratge.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra el nombre d'assignacions de memòria al llarg del temps.
Feu " +"clic i arrossegueu per a seleccionar un interval de temps per al filtratge." + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra el nombre d'assignacions temporals de memòria al llarg del temps. " +"Una assignació temporal és aquella que seguix immediatament la seua " +"desassignació corresponent, sense cap altra assignació entremig.
Feu clic " +"i arrossegueu per a seleccionar un interval de temps per al filtratge.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrat des de %2 a %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta filtrada)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Feu clic i arrossegueu per a seleccionar un interval de temps per al " +"filtratge." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consum: %2. Feu clic i arrossegueu per a seleccionar un interval de " +"temps per al filtratge." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Assignacions: %2. Feu clic i arrossegueu per a seleccionar un " +"interval de temps per al filtratge." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Assignacions temporals: %2. Feu clic i arrossegueu per a seleccionar " +"un interval de temps per al filtratge." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 assignacions en total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 assignacions temporals en total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 pics de consum de memòria" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 perduts en total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) assignacions a %3 i davall." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) assignacions temporals a %3 i davall." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contribució al pic de consum a %3 i davall." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) perduts a %3 i davall." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pic de memòria" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostra un gràfic de flames sobre les contribucions al pic de consum de " +"memòria en monticles de l'aplicació." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostra un gràfic de flames sobre la memòria en monticles perduda de " +"l'aplicació. Es considera que la memòria es perd quan no es desselecciona " +"mai." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostra un gràfic de flames sobre el nombre d'assignacions desencadenades per " +"funcions en el codi." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostra un gràfic de flames sobre el nombre d'assignacions temporals " +"desencadenades per funcions en el codi. Les assignacions es marquen com a " +"temporals quan estan seguides immediatament per la seua desassignació." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Seleccioneu l'origen de dades que s'ha de visualitzar en el gràfic de flames." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista de baix cap a dalt" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Activa la vista de baix cap a dalt del gràfic de flames. Quan açò no està " +"activat, de manera predeterminada està activada la vista de dalt cap a baix." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Reduïx la recursivitat" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Reduïx els marcs de la pila per a les funcions que es criden a si mateixes. " +"Quan açò no està activat, els marcs amb recursivitat es visualitzaran per " +"separat." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Llindar del cost: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"El llindar del cost definix un valor fraccional de retall. Els elements " +"amb un cost relatiu inferior a este valor no es mostraran en el gràfic de " +"flames. Açò es fa com una optimització per a generar ràpidament gràfics per " +"a conjunts de dades grans amb una sobrecàrrega de memòria baixa. Si calen " +"més detalls, reduïu el valor del llindar o definiu-lo a zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Busca..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Carca un símbol al gràfic de flames." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Restaura la vista" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Vista del Cridador / Cridat" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "s'està generant el gràfic de flames..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% d'un total de %3) assignacions coincidixen en la busca." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% d'un total de %3) coincidixen en la busca." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "IGU de Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un visor pels fitxers de dades de «heaptrack»." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor original, mantenidor" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Dades d'anàlisi de rendiment base a comparar amb altres fitxers." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Carrega la llista de supressions de fuites des del fitxer especificat. " +"Especifiqueu una supressió per línia i comenceu cada línia amb «leak:», és a " +"dir, utilitzeu el format de fitxer per a la supressió LSAN." + +# skip-rule: t-apo1,rst-link0italic,rst-italic2 +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignora les definicions de supressió que estan incrustades en el fitxer de " +"dades de Heaptrack. De manera predeterminada, Heaptrack copiarà les " +"supressions definides de manera opcional mitjançant un símbol «const char " +"*__lsan_default_suppressions()» en l'aplicació de depuració. Estes " +"s'aplicaran sempre en l'anàlisi sintàctica de les dades, llevat que " +"s'inhabilite explícitament esta característica mitjançant esta opció de la " +"línia d'ordres." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignora les definicions de supressió que estan integrades en Heaptrack. De " +"manera predeterminada, Heaptrack suprimirà certes pèrdues conegudes en les " +"biblioteques habituals del de sistema." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Fitxers que s'han de carregar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FITXER...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 assignacions de %2, amb un total de %3 assignades amb una mitjana de %4 " +"per assignació" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Mida de l'assignació requerida" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Nombre d'assignacions" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Obri el fitxer en l'editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depuració:
%1 " +"(annexat)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depuració:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
temps total d'execució:
%1, filtrat des de %2 a %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
temps total d'execució:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memòria total del sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
crides a funcions d'assignació:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
assignacions temporals:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
pic de consum de memòria en monticles:
%1 després %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
pic RSS (incloent-hi la sobrecàrrega de «heaptrack»):
%1" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta de consum de memòria en monticles:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
memòria total perduda:
%1 (%2 suprimida)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
memòria total perduda:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "No s'ha pogut analitzar el fitxer %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumida" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Mides" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "La dada d'entrada %1 no existix." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "La dada d'entrada %1 no és cap fitxer." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "La dada d'entrada %1 no es pot llegir." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "No s'ha pogut analitzar la supressió del fitxer." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Inhabilita les supressions incrustades" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Inhabilita les supressions integrades" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignora les definicions de supressió que estan integrades en Heaptrack. De " +"manera predeterminada, Heaptrack suprimirà certes pèrdues conegudes de les " +"biblioteques habituals del de sistema." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "S'està carregant el fitxer %1. Espereu..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 comparat amb %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "S'està tornant a analitzar el fitxer. Espereu..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegació pel codi" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalitzada..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automàtic (Sense nombre de línies)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegació personalitzada pel codi" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Especifiqueu l'ordre que s'utilitzarà per a la navegació pel codi, «%f» se " +"substituirà pel nom de fitxer, «%l» pel número de línia i «%c» pel número de " +"columna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Finestra principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Camí cap a un fitxer que conté les regles per a la supressió de fuites en el " +"format LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Obri les dades de Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Este camp especifica el fitxer de dades primàries de «heaptrack». " +"Estos fitxers s'anomenen heaptrack.$APP.$PID.gz o heaptrack." +"$APP.$PID.zst. Podeu crear estos fitxers amb l'anàlisi del rendiment de " +"l'aplicació, p. ex., via:

\n" +"
heaptrack <aplicació> ...
\n" +"

O, de manera alternativa, podeu annexar un procés en execució via

\n" +"
heaptrack --pid $(pidof <aplicació>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "camí/a/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"De manera opcional, podeu especificar un segon fitxer de dades " +"«heaptrack» per a comparar-lo. Si es definix, este fitxer s'utilitzarà com a " +"base i el seu cost es restarà dels costos de dades primaris." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dades d'anàlisi del rendiment:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Compara amb:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supressions:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "camí/a/supressions_lsan.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resum" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Llista de funcions que assignen la majoria de la memòria en un moment donat." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contribucions al pic" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Llista de funcions que perden la majoria de la memòria." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Pèrdues més grans de memòria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Llista de funcions que assignen la memòria més sovint." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Assignacions de memòria més freqüents" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Llista de funcions que produïxen la majoria de les assignacions temporals de " +"memòria." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Assignacions temporals més freqüents" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supressions" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "De baix a dalt" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtra per funció..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtra per fitxer..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtra per mòdul..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Cridador / Cridat" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "De dalt a baix" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Gràfic de flames" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Piles" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Pila seleccionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "Fi&txer" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Co&nfiguració" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtre" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "s'estan fusionant les assignacions... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "més que 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "s'està tornant a analitzar les dades" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "s'estan analitzant les dades" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 aprovat: %2/%3 gastat: %4 resta: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "s'estan fusionant les assignacions..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "s'està construint l'histograma..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "s'estan construint les taules..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Traça inversa" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"El nombre de vegades que una funció d'assignació s'ha cridat des d'esta " +"ubicació." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"El nombre d'assignacions temporals. Estes assignacions són seguides de " +"forma directa per un arbre sense cap altra assignació entremig." + +# Termcat: heap=memòria en monticle +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Les contribucions des d'una ubicació donada al consum en bytes de la " +"memòria en monticles màxima. Açò té en compte les desassignacions." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"La ubicació des de la qual s'ha cridat una funció d'assignació. El " +"símbol de la funció i la informació del fitxer poden ser desconeguts si " +"falta la informació de depuració quan es va executar «heaptrack»." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" a %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contribució al pic: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "perduts: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "assignacions: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporals: %1 (%2% de les assignacions, %3% del total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Traça inversa:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "cridat des d'una ubicació" +msgstr[1] "cridat des de %1 ubicacions" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% d'un total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (propi): %2
  %4% d'un total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusiu): %2
  %4% d'un total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbol: %1
binari: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 a %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/cs/heaptrack.po b/po/cs/heaptrack.po new file mode 100644 index 00000000..851d8a7a --- /dev/null +++ b/po/cs/heaptrack.po @@ -0,0 +1,1234 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Vít Pelčák , 2015, 2016, 2017, 2018, 2019. +# Vit Pelcak , 2021, 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-02-22 16:43+0100\n" +"Last-Translator: Vit Pelcak \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 22.12.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vít Pelčák" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "vit@pelcak.org" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Umístění" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Volající" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Volaný" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Špička" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Alokace" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Dočasné" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Alokace paměti" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Spotřebovaná paměť" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Dočasné alokace" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Uplynulý čas" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Celkem alokací paměti" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Celková spotřeba paměti" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Celkem alokací paměti" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bajtů)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportovat jako..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Zobrazit vysvětlivky" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Skládané grafy:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Vyčistit filtr" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Uložit %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Rastrový obrázek (*.png *.jpg *.tiff);;Vektorový obrázek (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Chyba při ukládání obrázku do %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Čas%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Spotřebovaná%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Alokace%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "Dočasné alokace%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 spotřeba paměti ve špičce" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Vyberte zdroj dat, která by měla být vyobrazena v plamenném grafu." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Sbalit rekurzi" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Hledat..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Přenastavit pohled" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Autorská práva 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Původní autor, správce" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Základní profil dat pro srovnání s jinými soubory." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Soubory k otevření" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[Soubor...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Počet alokací" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Otevřít soubor v editoru." + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Spotřebovaná" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Velikosti" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Vstupní data \"%1\" neexistují." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Vstupní data \"%1\" nejsou soubor." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Vstupní data \"%1\" nelze přečíst." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Vypnout zabudovaná potlačení" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Procházení kódem" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Vlastní..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatické (bez čísel řádků)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Vlastní procházení kódem" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "MainWindow" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Data profilu:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Porovnat s:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Shrnutí" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Nejvíc alokací paměti" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Nejvíce dočasných alokací" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Plamenný graf" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Soubor" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "&Nastavení" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtr" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "slučuji alokace... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "celkem" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B až 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B až 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B až 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B až 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B až 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B až 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "29B až 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "9B až 512B" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "více než 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "zpracovávám data" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "slučuji alokace..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace:" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" v %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% z %3 celkem" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbol: %1
binárka: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 v %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/da/heaptrack.po b/po/da/heaptrack.po new file mode 100644 index 00000000..d42b28ea --- /dev/null +++ b/po/da/heaptrack.po @@ -0,0 +1,1568 @@ +# translation of heaptrack.po to Danish +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# scootergrisen, 2018. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2018-01-26 20:51+0200\n" +"Last-Translator: scootergrisen\n" +"Language-Team: Danish\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "scootergrisen" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Placering" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allokeringer (selv)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Midlertidige (selv)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Spidspunkt (selv)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Lækket (selv)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allokeringer (inkl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Midlertidige (inkl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Spidspunkt (inkl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Lækket (inkl.)" + +#: gui/callercalleemodel.cpp:63 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +"når der mangler fejlretningsinformation." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Antal gange en programfunktion blev kaldt direkte fra denne placering." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Antal direkte midlertidige allokeringer. Disse allokeringer efterfølges " +"direkte af en ledig uden andre mellemliggende allokeringer" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Den maksimale heap-hukommelse i bytes forbrugt fra allokeringer som har " +"sin oprindelse direkte på denne placering. Der tages højde for " +"deallokeringer." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Bytene som er allokeret direkte på denne placering som ikke er blevet " +"deallokeret." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"De inkluderende antal gange en allokeringsfunktion blev kaldt fra denne " +"placering eller funktioner kaldt herfra." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Antal inkluderende midlertidige allokeringer. Disse allokeringer " +"efterfølges direkte af en ledig uden andre mellemliggende allokeringer" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Den inkluderende maksimale heap-hukommelse i bytes forbrugt fra " +"allokeringer som har sin oprindelse direkte på denne placering eller fra " +"funktioner kaldt herfra. Der tages højde for deallokeringer." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Bytene som er allokeret på denne placering som ikke er blevet " +"deallokeret." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Spidspunkt" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Lækket" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Allokeringer" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Midlertidige" + +#: gui/callercalleemodel.h:170 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +"når der mangler fejlretningsinformation." + +#: gui/callercalleemodel.h:356 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +"når der mangler fejlretningsinformation." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Hukommelsesallokeringer" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Hukommelse forbrugt" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Midlertidige allokeringer" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Forløbet tid" + +#: gui/chartmodel.cpp:83 +#, fuzzy, kde-format +#| msgid "Most Memory Allocations" +msgid "Total Memory Allocations" +msgstr "Fleste hukommelsesallokeringer" + +#: gui/chartmodel.cpp:85 +#, fuzzy, kde-format +#| msgid "%1 contribution to peak consumption" +msgid "Total Memory Consumption" +msgstr "%1 bidrag til spidspunktsforbrug" + +#: gui/chartmodel.cpp:87 +#, fuzzy, kde-format +#| msgid "Most Temporary Allocations" +msgid "Total Temporary Allocations" +msgstr "Fleste midlertidige allokeringer" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allokeringer i alt efter %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 midlertidige allokeringer i alt efter %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 forbrugt i alt efter %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 allokeringer efter %3 fra:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 midlertidige allokeringer efter %3 fra:

" +"%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 forbrugt efter %3 fra:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, fuzzy, kde-format +#| msgid "filter by function..." +msgid "Filter In On Selection" +msgstr "filtrér efter funktion..." + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, fuzzy, kde-format +#| msgid "Reset View" +msgid "Reset Filter" +msgstr "Nulstil visning" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to save the image to %1" +msgstr "Kunne ikke fortolke filen %1." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, fuzzy, kde-format +#| msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgid "" +"Temporary Allocations%1%2%3" +msgstr "
midlertidige allokeringer:
%1 (%2%, %3/s)
" + +#: gui/chartwidget.cpp:441 +#, fuzzy, kde-format +#| msgid "Shows the heap memory consumption over time." +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "Viser heap-hukommelsesforbruget over tid." + +#: gui/chartwidget.cpp:445 +#, fuzzy, kde-format +#| msgid "Shows number of memory allocations over time." +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "Viser antallet af hukommelsesallokeringer over tid." + +#: gui/chartwidget.cpp:449 +#, fuzzy, kde-format +#| msgid "" +#| "Shows number of temporary memory allocations over time. A temporary " +#| "allocation is one that is followed immediately by its corresponding " +#| "deallocation, without other allocations happening in-between." +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Viser antallet af midlertidige hukommelsesallokeringer over tid. En " +"midlertidig allokering er en som ikke straks er efterfulgt af dens " +"tilhørende deallokering, uden andre mellemliggende allokeringer" + +#: gui/chartwidget.cpp:471 +#, fuzzy, kde-format +#| msgid "%1 allocations from %2 in %3" +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 allokeringer fra %2 i %3" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 allokeret i alt" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 midlertidige allokeringer i alt" + +#: gui/flamegraph.cpp:179 +#, fuzzy, kde-format +#| msgid "%1 contribution to peak consumption" +msgid "%1 peak memory consumption" +msgstr "%1 bidrag til spidspunktsforbrug" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 lækket i alt" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) allokeringer i %3 og under." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) midlertidige allokeringer i %3 og under." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) bidrag til spidspunktsforbrug i %3 og under." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) lækket i %3 og under." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Hukommelsesspidspunkt" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Vis en flammegraf over bidragene til spidspunktets heap-hukommelsesforbrug " +"for dit program." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Vis en flammegraf over lækket heap-hukommelse for dit program. Hukommelse " +"betragtes som lækket når den aldrig blev deallokeret. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Vis en flammegraf over antallet af allokeringer som er blevet udløst af " +"funktioner i din kode." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Vis en flammegraf over antallet af midlertidige allokeringer som er blevet " +"udløst af funktioner i din kode. Allokeringer mærkes som midlertidige når de " +"straks er efterfulgt af deres deallokering." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Vælg datakilden som skal visualiseres i flammegrafen." + +#: gui/flamegraph.cpp:467 +#, fuzzy, kde-format +#| msgid "Bottom-Down View" +msgid "Bottom-Up View" +msgstr "Nedefra og ned-visning" + +#: gui/flamegraph.cpp:468 +#, fuzzy, kde-format +#| msgid "" +#| "Enable the bottom-down flame graph view. When this is unchecked, the top-" +#| "down view is enabled by default." +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Aktivér flammegrafens nedefra og ned-visningen. Når den er fravalgt, " +"aktiveres oppefra og ned-visningen som standard." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Sammenfold gentagelse" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Sammenfold stakrammer for funktioner som kalder sig selv. Når den er " +"fravalgt, visualiseres gentagne rammer separat." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Omkostningstærskel: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Omkostningstærsklen angiver en kommatalsværdi til afklipning. Poster med " +"en relativ omkostning under denne værdi vises ikke i flammegrafen. Det gøres " +"som en optimering for hurtigt at generere grafer til store datasæt med lav " +"hukommelses-overhead. Hvis du har brug for flere detaljer, så øg " +"tærskelværdien, eller sæt den til nul." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Søg..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Søg efter et symbol i flammegrafen." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Nulstil visning" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, fuzzy, kde-format +#| msgid "Caller / Callee" +msgid "View Caller/Callee" +msgstr "Kalder/modtager" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "genererer flammegraf..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2 af samlet %3) allokeringer matchet af søgning." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2 af samlet %3) matchet af søgning." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack-brugerflade" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "En visualisering til heaptrack-datafiler." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Ophavsret 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Oprindelig forfatter, vedligeholder" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Grundlæggende profildata til at sammenligne andre filer med." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Filer som skal indlæses" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FIL...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Anmodet allokeringsstørrelse" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Antal allokeringer" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Åbn fil i redigeringsprogram" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
fejlrettes:
%1 " +"(tilkoblet)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
fejlrettes:
%1
" + +#: gui/mainwindow.cpp:401 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
samlet kørselstid:
%1s
" + +#: gui/mainwindow.cpp:406 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1
" +msgstr "
samlet kørselstid:
%1s
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
samlet systemhukommelse:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
kald til allokeringsfunktioner:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
midlertidige allokeringer:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, fuzzy, kde-format +#| msgid "
peak heap memory consumption:
%1 after %2s
" +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
spidspunkts heap-hukommelsesforbrug:
%1 efter %2s
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
spidspunkts RSS (inklusiv heaptrack-overhead):
%1
" + +#: gui/mainwindow.cpp:435 +#, fuzzy, kde-format +#| msgid "
peak heap memory consumption:
%1 after %2s
" +msgid "
memory consumption delta:
%1
" +msgstr "" +"
spidspunkts heap-hukommelsesforbrug:
%1 efter %2s
" + +#: gui/mainwindow.cpp:439 +#, fuzzy, kde-format +#| msgid "
total memory leaked:
%1
" +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
samlet hukommelse lækket:
%1
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
samlet hukommelse lækket:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Kunne ikke fortolke filen %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Forbrugt" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Størrelser" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Inputdataen %1 findes ikke." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Inputdataen %1 er ikke en fil." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Inputdataen %1 kan ikke læses." + +#: gui/mainwindow.cpp:597 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to parse suppression file." +msgstr "Kunne ikke fortolke filen %1." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Indlæser filen %1, vent venligst..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 sammenlignet med %2" + +#: gui/mainwindow.cpp:703 +#, fuzzy, kde-format +#| msgid "Loading file %1, please wait..." +msgid "Reparsing file, please wait..." +msgstr "Indlæser filen %1, vent venligst..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr "/%1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "HovedVindue" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Åbn Heaptrack-data" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, fuzzy, kde-format +#| msgid "" +#| "

This field specifies the primary heaptrack data file. These files " +#| "are called heaptrack.$APP.$PID.gz. You can produce such a file " +#| "by profiling your application, e.g. via:

\n" +#| "
heaptrack <yourapplication> ...
\n" +#| "

Or, alternatively, you can attach to a running process via

\n" +#| "
heaptrack --pid $(pidof <yourapplication>)
" +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Feltet angiver den primære heaptrack-datafil. Filerne kaldes " +"heaptrack.$APP.$PID.gz. Du kan producere sådan en fil ved at " +"profilerer dit program, f.eks. via:

\n" +"
heaptrack <ditprogram> ...
\n" +"

Eller som alternativ kan du koble til en kørende proces via

\n" +"
heaptrack --pid $(pid af <ditprogram>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, fuzzy, kde-format +#| msgid "path/to/heaptrack.$APP.$PID.gz" +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "sti/til/heaptrack.$APP.$PID.gz" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Du kan valgfrit angive en anden heaptrack-datafil til sammenligning. " +"Hvis den er sat, bruges denne fil som et grundlag og dens omkostninger " +"bliver trukket fra de primære dataomkostninger." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profil&data:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Sammenlign med:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Opsummering" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Liste over funktioner som allokerede mest hukommelse på et givent tidspunkt." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Spidspunktsbidrag" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Liste over funktioner som lækker mest hukommelse." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Største hukommelseslæk" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Liste over funktioner som oftest allokerer hukommelse." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Fleste hukommelsesallokeringer" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Liste over funktioner som producerede flest midlertidige " +"hukommelsesallokeringer." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Fleste midlertidige allokeringer" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Nedefra og op" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrér efter funktion..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrér efter fil..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrér efter modul..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Kalder/modtager" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Oppefra og ned" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Flammegraf" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&takke" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Valgte stak:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Fil" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, fuzzy, kde-format +#| msgid "merging allocations..." +msgid "merging allocations... %1%" +msgstr "sammenlægger allokeringer..." + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "samlet" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0 B til 8 B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9 B til 16 B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17 B til 32 B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33 B til 64 B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65 B til 128 B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129 B til 256 B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257 B til 512 B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 B til 1 KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "mere end 1 KB" + +#: gui/parser.cpp:645 +#, fuzzy, kde-format +#| msgid "parsing data..." +msgid "reparsing data" +msgstr "fortolker data..." + +#: gui/parser.cpp:645 +#, fuzzy, kde-format +#| msgid "parsing data..." +msgid "parsing data" +msgstr "fortolker data..." + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "sammenlægger allokeringer..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "bygger størrelseshistogram..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "bygger skemaer..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Antal gange en allokeringsfunktion blev kaldt fra denne placering." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Antal midlertidige allokeringer. Disse allokeringer efterfølges direkte " +"af en ledig uden andre mellemliggende allokeringer" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Bidragene fra en given placering til det maksimale heap-" +"hukommelsesforbrug i bytes. Der tages højde for deallokeringer." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Placeringen hvorfra en allokeringsfunktion blev kaldt. Funktionssymbol " +"og filinformation kan være ukendt når fejlretningsinformation manglede da " +"heaptrack blev kørt." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, fuzzy, kde-format +#| msgctxt "1: function, 2: module" +#| msgid "" +#| "%1\n" +#| " in %2" +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" i %2" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "spidspunktsbidrag: %1 (%2% af samlet)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "lækket: %1 (%2% af samlet)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "allokeringer: %1 (%2% af samlet)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "midlertidige: %1 (%2 af allokeringer, %3% af samlet)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "kaldt fra én placering" +msgstr[1] "kaldt fra %1 placeringer" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, fuzzy, kde-format +#| msgctxt "1: function, 2: module" +#| msgid "" +#| "%1\n" +#| " in %2" +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" +"%1\n" +" i %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#, fuzzy +#~| msgid "heaptrack.*.*.gz" +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz" + +#, fuzzy +#~| msgid "%1 allocations from %2 in %3" +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 allokeringer fra %2 i %3" + +#, fuzzy +#~| msgid "%1 in ?? (%2)" +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 i ?? (%2)" + +#, fuzzy +#~| msgid "%1 in %2:%3 (%4)" +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 i %2:%3 (%4)" + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +#~ "når der mangler fejlretningsinformation." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Modulet, dvs. kørbar eller delt bibliotek, hvorfra en " +#~ "allokeringsfunktion blev kaldt." + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +#~ "når der mangler fejlretningsinformation." + +#~ msgid "Function" +#~ msgstr "Funktion" + +#~ msgid "Module" +#~ msgstr "Modul" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Forælderfunktionen som kaldte en allokeringsfunktion. Kan være ukendt " +#~ "når der mangler fejlretningsinformation." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " i %2" + +#~ msgid "File" +#~ msgstr "Fil" + +#~ msgid "Line" +#~ msgstr "Linje" + +#~ msgid "Allocated (Self)" +#~ msgstr "Allokeret (selv)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Allokeret (inkl.)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Filen hvor allokeringsfunktionen blev kaldt fra. Kan være når tom når " +#~ "der mangler fejlretningsinformation." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Linjenummeret hvor allokeringsfunktionen blev kaldt fra. Kan være når " +#~ "tom når der mangler fejlretningsinformation." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Summen af alle bytes som er allokeret direkte fra denne placering, " +#~ "deallokeringer ignoreres." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Den inkluderende sum af alle bytes som er allokeret fra denne " +#~ "placering eller funktioner kaldt herfra, deallokeringer ignoreres." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " på %2:%3\n" +#~ " i %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inklusiv: allokeret %1 over %2 kald (%3 midlertidige, dvs. %4%), " +#~ "spidspunkt på %5, lækket %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "selv: allokeret %1 over %2 kald (%3 midlertidige, dvs. %4%), spidspunkt " +#~ "på %5, lækket %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Hukommelse allokeret" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 allokeret i alt efter %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 allokeret efter %3 fra:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Viser samlet hukommelse allokeret over tid. Værdien ignorerer " +#~ "deallokeringer og måler bare gennemløb af heap-allokering." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) allokeret i %3 og under." + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 allokeret i alt" + +#~ msgid "Allocated" +#~ msgstr "Allokeret" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Vis en flammegraf over den samlede hukommelse allokeret af funktioner i " +#~ "din kode. Det indsamler alle hukommelsesallokeringer og ignorerer " +#~ "deallokeringer." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 allokeringer fra %2 på %3:%4 i %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
bytes allokeret i alt (ignorerer deallokeringer):
%1 " +#~ "(%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Liste over funktioner som samlet set allokerede mest hukommelse, " +#~ "deallokeringer ignoreres." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Mest hukommelse allokeret" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Summen af alle bytes som er allokeret fra denne placering, " +#~ "deallokeringer ignoreres." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "allokeret: %1 (%2 af samlet)\n" diff --git a/po/de/heaptrack.po b/po/de/heaptrack.po new file mode 100644 index 00000000..a1031893 --- /dev/null +++ b/po/de/heaptrack.po @@ -0,0 +1,1493 @@ +# Burkhard Lück , 2015, 2016, 2017, 2018, 2019, 2021. +# Frederik Schwarzer , 2015, 2016, 2018, 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-02-26 03:08+0100\n" +"Last-Translator: Frederik Schwarzer \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 21.08.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Deutsches KDE-Übersetzerteam" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde-i18n-de@kde.org" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Adresse" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Allocations (Self)" +msgstr "Zuordnungen" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, fuzzy, kde-format +#| msgid "Temporary" +msgid "Temporary (Self)" +msgstr "Temporär" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, fuzzy, kde-format +#| msgid "Temporary" +msgid "Peak (Self)" +msgstr "Temporär" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, fuzzy, kde-format +#| msgid "Allocated" +msgid "Leaked (Self)" +msgstr "Zugeordnet" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Allocations (Incl.)" +msgstr "Zuordnungen" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, fuzzy, kde-format +#| msgid "Temporary" +msgid "Temporary (Incl.)" +msgstr "Temporär" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, fuzzy, kde-format +#| msgid "Temporary" +msgid "Peak (Incl.)" +msgstr "Temporär" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, fuzzy, kde-format +#| msgid "Allocated" +msgid "Leaked (Incl.)" +msgstr "Zugeordnet" + +#: gui/callercalleemodel.cpp:63 +#, fuzzy, kde-format +#| msgid "" +#| "The file where the allocation function was called from. May be empty " +#| "when debug information is missing." +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Die Datei, aus der die allozierende Funktion aufgerufen wurde. Kann leer " +"sein, wenn Debug-Informationen fehlen." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Die Bytes, die genau an dieser Stelle alloziert und nicht wieder " +"freigegeben wurden." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Die Bytes, die an dieser Stelle alloziert und nicht wieder freigegeben " +"wurden." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Aufrufer" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Aufgerufener" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Spitzenwert" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Zuordnungen" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporär" + +#: gui/callercalleemodel.h:170 +#, fuzzy, kde-format +#| msgid "" +#| "The file where the allocation function was called from. May be empty " +#| "when debug information is missing." +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Die Datei, aus der die allozierende Funktion aufgerufen wurde. Kann leer " +"sein, wenn Debug-Informationen fehlen." + +#: gui/callercalleemodel.h:356 +#, fuzzy, kde-format +#| msgid "" +#| "The file where the allocation function was called from. May be empty " +#| "when debug information is missing." +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Die Datei, aus der die allozierende Funktion aufgerufen wurde. Kann leer " +"sein, wenn Debug-Informationen fehlen." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Speicherzuordnungen" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Belegter Speicher" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Temporäre Speicherzuordnungen" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Verstrichene Zeit" + +#: gui/chartmodel.cpp:83 +#, fuzzy, kde-format +#| msgid "Memory Allocations" +msgid "Total Memory Allocations" +msgstr "Speicherzuordnungen" + +#: gui/chartmodel.cpp:85 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "Total Memory Consumption" +msgstr "%1 Zuordnungen gesamt" + +#: gui/chartmodel.cpp:87 +#, fuzzy, kde-format +#| msgid "Temporary Allocations" +msgid "Total Temporary Allocations" +msgstr "Temporäre Speicherzuordnungen" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 Bytes)" + +#: gui/chartmodel.cpp:174 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 allocations in total after %2" +msgstr "%1 Zuordnungen gesamt" + +#: gui/chartmodel.cpp:176 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 temporary allocations in total after %2" +msgstr "%1 Zuordnungen gesamt" + +#: gui/chartmodel.cpp:178 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 consumed in total after %2" +msgstr "%1 Zuordnungen gesamt" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 Speicherzuordnungen nach %3 von:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 temporäre Speicherzuordnungen nach %3 von:

%1

" + +#: gui/chartmodel.cpp:192 +#, fuzzy, kde-format +#| msgid "" +#| "%2 allocated after %3 from:

%1

" +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 zugeordnet nach %3 von:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, fuzzy, kde-format +#| msgid "filter by function..." +msgid "Filter In On Selection" +msgstr "Nach Funktion filtern ..." + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Filter zurücksetzen" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to save the image to %1" +msgstr "Das Einlesen der Datei %1 ist fehlgeschlagen." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "" +"Temporary Allocations%1%2%3" +msgstr "Speicherleck gesamt: %1" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "%1 Zuordnungen gesamt" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, fuzzy, kde-format +#| msgid "%1 allocations from %2 in %3 (%4)" +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 Speicherzuordnungen von %2 in %3 (%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 Zuordnungen gesamt" + +#: gui/flamegraph.cpp:177 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 temporary allocations in total" +msgstr "%1 Zuordnungen gesamt" + +#: gui/flamegraph.cpp:179 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 peak memory consumption" +msgstr "%1 Zuordnungen gesamt" + +#: gui/flamegraph.cpp:181 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "%1 leaked in total" +msgstr "%1 Zuordnungen gesamt" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2 %) Zuordnungen in %3 und darunter." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2 %) temporäre Zuordnungen in %3 und darunter." + +#: gui/flamegraph.cpp:244 +#, fuzzy, kde-format +#| msgctxt "%1: number of allocations, %2: function label" +#| msgid "%1 allocations in %2 and below." +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 Zuordnungen in %2 und darunter." + +#: gui/flamegraph.cpp:248 +#, fuzzy, kde-format +#| msgctxt "%1: number of allocations, %2: function label" +#| msgid "%1 allocations in %2 and below." +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 Zuordnungen in %2 und darunter." + +#: gui/flamegraph.cpp:428 +#, fuzzy, kde-format +#| msgid "Largest Memory Leaks" +msgid "Memory Peak" +msgstr "Größte Speicherlecks" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Suchen ..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Ansicht zurücksetzen" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Aufrufer / Aufgerufener" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack-Benutzeroberfläche" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Ein Visualisierer für Heaptrack-Datendateien." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Ursprünglicher Autor und Betreuer" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Zu ladende Dateien" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[DATEI ...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Angeforderte Zuordnungsgröße" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Anzahl der Speicherzuordnungen" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Datei in Editor öffnen" + +#: gui/mainwindow.cpp:394 +#, fuzzy, kde-format +#| msgid "
debuggee:
%1
" +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
Fehlersuche in:
%1
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
Fehlersuche in:
%1
" + +#: gui/mainwindow.cpp:401 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
Gesamte Laufzeit:
%1 s
" + +#: gui/mainwindow.cpp:406 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1
" +msgstr "
Gesamte Laufzeit:
%1 s
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
Gesamter Systemspeicher:
%1
" + +#: gui/mainwindow.cpp:415 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "Speicherleck gesamt: %1" + +#: gui/mainwindow.cpp:418 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "Speicherleck gesamt: %1" + +#: gui/mainwindow.cpp:428 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "Speicherleck gesamt: %1" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
memory consumption delta:
%1
" +msgstr "Speicherleck gesamt: %1" + +#: gui/mainwindow.cpp:439 +#, fuzzy, kde-format +#| msgid "
total memory leaked:
%1
" +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
Speicherleck gesamt:
%1
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
Speicherleck gesamt:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Das Einlesen der Datei %1 ist fehlgeschlagen." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Belegt" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Größen" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Die Eingabedaten %1 existieren nicht." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Die Eingabedaten %1 sind keine Datei." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Die Eingabedaten %1 sind nicht lesbar." + +#: gui/mainwindow.cpp:597 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to parse suppression file." +msgstr "Das Einlesen der Datei %1 ist fehlgeschlagen." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Die Datei %1 wird geladen, bitte warten ..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 verglichen mit %2" + +#: gui/mainwindow.cpp:703 +#, fuzzy, kde-format +#| msgid "Loading file %1, please wait..." +msgid "Reparsing file, please wait..." +msgstr "Die Datei %1 wird geladen, bitte warten ..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Quelltextnavigation" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Benutzerdefiniert ..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Hauptfenster" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Heaptrack-Daten öffnen" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "pfad/zu/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profil&daten:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Vergleichen mit:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Zusammenfassung" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "Peak Contributions" +msgstr "%1 Zuordnungen gesamt" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Größte Speicherlecks" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, fuzzy, kde-format +#| msgid "Memory Allocations" +msgid "Most Memory Allocations" +msgstr "Speicherzuordnungen" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, fuzzy, kde-format +#| msgid "Temporary Allocations" +msgid "Most Temporary Allocations" +msgstr "Temporäre Speicherzuordnungen" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "Nach Funktion filtern ..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "Nach Datei filtern ..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "Nach Modul filtern ..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Aufrufer / Aufgerufener" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tacks" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Ausgewählter Stack:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Datei" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Ei&nstellungen" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, fuzzy, kde-format +#| msgid "Memory Allocations" +msgid "merging allocations... %1%" +msgstr "Speicherzuordnungen" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "gesamt" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B bis 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B bis 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B bis 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B bis 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B bis 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B bis 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B bis 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B bis 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "mehr als 1KB" + +#: gui/parser.cpp:645 +#, fuzzy, kde-format +#| msgid "parsing data..." +msgid "reparsing data" +msgstr "Daten werden verarbeitet ..." + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "Daten werden verarbeitet" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, fuzzy, kde-format +#| msgid "Memory Allocations" +msgid "merging allocations..." +msgstr "Speicherzuordnungen" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Rückverfolgung" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" in %2 (%3)" + +#: gui/treemodel.cpp:159 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "%1 Zuordnungen gesamt" + +#: gui/treemodel.cpp:160 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "leaked: %1 (%2% of total)\n" +msgstr "%1 Zuordnungen gesamt" + +#: gui/treemodel.cpp:161 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "allocations: %1 (%2% of total)\n" +msgstr "%1 Zuordnungen gesamt" + +#: gui/treemodel.cpp:162 +#, fuzzy, kde-format +#| msgid "%1 allocations in total" +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "%1 Zuordnungen gesamt" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Rückverfolgung:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" +msgstr[1] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 in %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 Speicherzuordnungen von %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 in %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbol" + +#~ msgid "Binary" +#~ msgstr "Programmdatei" + +#, fuzzy +#~| msgid "" +#~| "The file where the allocation function was called from. May be empty " +#~| "when debug information is missing." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Die Datei, aus der die allozierende Funktion aufgerufen wurde. Kann " +#~ "leer sein, wenn Debug-Informationen fehlen." + +#, fuzzy +#~| msgid "" +#~| "The file where the allocation function was called from. May be empty " +#~| "when debug information is missing." +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Die Datei, aus der die allozierende Funktion aufgerufen wurde. Kann " +#~ "leer sein, wenn Debug-Informationen fehlen." + +#~ msgid "Function" +#~ msgstr "Funktion" + +#~ msgid "Module" +#~ msgstr "Modul" + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " in %2" + +#~ msgid "File" +#~ msgstr "Datei" + +#~ msgid "Line" +#~ msgstr "Zeile" + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Self)" +#~ msgstr "Zugeordnet" + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Incl.)" +#~ msgstr "Zugeordnet" + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Die Zeilennummer, aus der die allozierende Funktion aufgerufen wurde. " +#~ "Kann leer sein, wenn Debug-Informationen fehlen." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " in %2:%3\n" +#~ " in %4" + +#~ msgid "Memory Allocated" +#~ msgstr "Zugeordneter Speicher" + +#, fuzzy +#~| msgid "%1 allocated in total" +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 Zuordnungen gesamt" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 zugeordnet nach %3 von:

%1

" + +#, fuzzy +#~| msgctxt "%1: number of allocations, %2: function label" +#~| msgid "%1 allocations in %2 and below." +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 Zuordnungen in %2 und darunter." + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 Zuordnungen gesamt" + +#~ msgid "Allocated" +#~ msgstr "Zugeordnet" + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 Speicherzuordnungen von %2 bei %3:%4 in %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
Bytes zugeordnet gesamt (Freigaben ignoriert):
%1 (%2/" +#~ "s)
" + +#, fuzzy +#~| msgid "Memory Allocated" +#~ msgid "Most Memory Allocated" +#~ msgstr "Zugeordneter Speicher" + +#, fuzzy +#~| msgid "%1 allocations in total" +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "%1 Zuordnungen gesamt" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Heaptrack-Ausgabedatei öffnen" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Heaptrack-Datendateien (heaptrack.*)" + +#~ msgid "debuggee: %1" +#~ msgstr "Fehlersuche in: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "Gesamte Laufzeit: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 um %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Zuordnungen [-]" + +#, fuzzy +#~| msgid "Memory Allocations" +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Speicherzuordnungen" + +#~ msgid "Allocated [B]" +#~ msgstr "Zugeordnet [B]" + +#~ msgid "time in ms" +#~ msgstr "Zeit in ms" + +#~ msgid "memory heap size" +#~ msgstr "Heap-Speichergröße" diff --git a/po/en_GB/heaptrack.po b/po/en_GB/heaptrack.po new file mode 100644 index 00000000..587e2d9f --- /dev/null +++ b/po/en_GB/heaptrack.po @@ -0,0 +1,1584 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Steve Allewell , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-12-31 15:54+0000\n" +"Last-Translator: Steve Allewell \n" +"Language-Team: British English \n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 21.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Steve Allewell" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "steve.allewell@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Location" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allocations (Self)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporary (Self)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Peak (Self)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Leaked (Self)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allocations (Incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporary (Incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Peak (Incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Leaked (Incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"The number of times an allocation function was directly called from this " +"location." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"The bytes allocated directly at this location that have not been " +"deallocated." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"The bytes allocated at this location that have not been deallocated." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Caller" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Callee" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Peak" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Leaked" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Allocations" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporary" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Memory Allocations" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memory Consumed" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Temporary Allocations" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Elapsed Time" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total Memory Allocations" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total Memory Consumption" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total Temporary Allocations" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allocations in total after %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 temporary allocations in total after %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumed in total after %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 allocations after %3 from:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 temporary allocations after %3 from:

%1" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumed after %3 from:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Export As..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Show legend" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Show total cost graph" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Show detailed cost graph" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Stacked diagrams:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filter In On Selection" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reset Filter" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Save %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Failed to save the image to %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "StartEndDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Time%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumed%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Allocations%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Temporary Allocations%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtered from %2 to %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (filtered delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Click and drag to select time range for filtering." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 allocations in total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 temporary allocations in total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 peak memory consumption" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 leaked in total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) allocations in %3 and below." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) temporary allocations in %3 and below." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contribution to peak consumption in %3 and below." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) leaked in %3 and below." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Memory Peak" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Select the data source that should be visualised in the flame graph." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Bottom-Up View" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Enable the bottom-up flame graph view. When this is unticked, the top-down " +"view is enabled by default." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Collapse Recursion" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Cost Threshold: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimisation to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Search..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Search the flame graph for a symbol." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Reset View" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "View Caller/Callee" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "generating flame graph..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% of total of %3) allocations matched by search." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% of total of %3) matched by search." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack GUI" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "A visualiser for heaptrack data files." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Original author, maintainer" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Base profile data to compare other files to." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analysing the data, unless " +"this feature is explicitly disabled using this command line option." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Files to load" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FILE...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Requested Allocation Size" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Number of Allocations" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Open file in editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
debuggee:
%1 " +"(attached)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
debuggee:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
total runtime:
%1, filtered from %2 to %3 (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
total runtime:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
total system memory:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
calls to allocation functions:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
temporary allocations:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
peak heap memory consumption:
%1 after %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
peak RSS (including heaptrack overhead):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
memory consumption delta:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
total memory leaked:
%1 (%2 suppressed)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
total memory leaked:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Failed to parse file %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumed" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Sizes" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Input data %1 does not exist." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Input data %1 is not a file." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Input data %1 is not readable." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Failed to parse suppression file." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Disable Embedded Suppressions" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Disable Builtin Suppressions" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Loading file %1, please wait..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 compared to %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Reparsing file, please wait..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Code Navigation" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Custom..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatic (No Line numbers)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Custom Code Navigation" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "MainWindow" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "Path to a file containing leak suppression rules in the LSAN format." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Open Heaptrack Data" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "path/to/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profile &Data:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Compare to:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Suppressions:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "path/to/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Summary" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "List of functions that allocated the most memory at a given time." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Peak Contributions" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "List of functions that leak the most memory." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Largest Memory Leaks" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "List of functions that allocate memory most often." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Most Memory Allocations" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "List of functions that produced the most temporary memory allocations." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Most Temporary Allocations" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Suppressions" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Bottom-Up" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filter by function..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filter by file..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filter by module..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Caller / Callee" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Top-Down" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Flame Graph" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tacks" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Selected Stack:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&File" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Setti&ngs" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "merging allocations... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B to 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B to 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B to 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B to 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B to 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B to 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B to 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B to 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "more than 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "reparsing data" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "parsing data" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 pass: %2/%3 spent: %4 remaining: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "merging allocations..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "building size histogram..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "building charts..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"The number of times an allocation function was called from this location." +"" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" in %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "peak contribution: %1 (%2% of total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "leaked: %1 (%2% of total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "allocations: %1 (%2% of total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporary: %1 (%2% of allocations, %3% of total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "called from one location" +msgstr[1] "called from %1 locations" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% out of %3 total" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (self): %2
  %4% out of %3 total" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusive): %2
  %4% out of %3 total" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbol: %1
binary: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 in %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 allocations from %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 in %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbol" + +#~ msgid "Binary" +#~ msgstr "Binary" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "The name of the executable the symbol resides in." + +#~ msgid "Function" +#~ msgstr "Function" + +#~ msgid "Module" +#~ msgstr "Module" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " in %2" + +#~ msgid "File" +#~ msgstr "File" + +#~ msgid "Line" +#~ msgstr "Line" + +#~ msgid "Allocated (Self)" +#~ msgstr "Allocated (Self)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Allocated (Incl.)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Memory Allocated" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 allocated in total after %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 allocated after %3 from:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) allocated in %3 and below." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 contribution to peak consumption" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 allocated in total" + +#~ msgid "Allocated" +#~ msgstr "Allocated" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 allocations from %2 at %3:%4 in %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Most Memory Allocated" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "allocated: %1 (%2% of total)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Open Heaptrack Output File" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Heaptrack data files (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Graphs" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" + +#~ msgid "debuggee: %1" +#~ msgstr "debuggee: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "total runtime: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 at %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Allocations [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Temporary Allocations [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Leaked [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Allocated [B]" + +#~ msgid "time in ms" +#~ msgstr "time in ms" + +#~ msgid "memory heap size" +#~ msgstr "memory heap size" diff --git a/po/es/heaptrack.po b/po/es/heaptrack.po new file mode 100644 index 00000000..a17d967b --- /dev/null +++ b/po/es/heaptrack.po @@ -0,0 +1,1618 @@ +# Spanish translations for heaptrack.po package. +# Copyright (C) 2015 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Automatically generated, 2015. +# Eloy Cuadra , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-05 04:58+0200\n" +"Last-Translator: Eloy Cuadra \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.08.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Eloy Cuadra" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ecuadra@eloihr.net" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Ubicación" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Asignaciones (propias)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporales (propias)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pico (propio)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Fugada (propia)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Asignaciones (incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporales (incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pico (incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Fugada (incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"El símbolo padre que ha llamado a una función de asignación. El nombre " +"de la función puede estar sin resolver cuando falta la información de " +"depuración." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"El número de veces que se ha llamado directamente a una función de " +"asignación desde esta ubicación." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El número de asignaciones temporales directas. Estas asignaciones están " +"seguidas directamente por un espacio libre sin otras asignaciones entre " +"ambos." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"El tamaño máximo de memoria dinámica en bytes consumida por las " +"asignaciones que se han realizado directamente desde esta ubicación. Se " +"tienen en cuenta las liberaciones de memoria realizadas." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Los bytes asignados directamente en esta ubicación que no se han " +"liberado." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"El número de veces incluidas que se ha llamado una función de asignación " +"desde esta ubicación." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"El número de asignaciones temporales incluidas. Estas asignaciones están " +"seguidas directamente por un espacio libre sin otras asignaciones entre " +"ambos." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"El tamaño máximo de memoria dinámica incluida en bytes consumida por las " +"asignaciones que se han realizado desde esta ubicación. Se tienen en cuenta " +"las liberaciones de memoria realizadas." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Los bytes asignados en esta ubicación que no se han liberado." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Función que llama" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Función llamada" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pico" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Fugada" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Asignaciones" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporal" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"La posición del %1. El nombre de la función puede estar sin resolver cuando " +"falta la información de depuración." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"La posición del código fuente que ha llamado a una función de " +"asignación. Puede ser desconocida cuando falta la información de depuración." +"" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Asignaciones de memoria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memoria consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Asignaciones temporales" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tiempo transcurrido" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total de asignaciones de memoria" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total de consumo de memoria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total de asignaciones temporales" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 asignaciones en total tras %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 asignaciones temporales en total tras %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumidos en total tras %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 asignaciones tras %3 de:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 asignaciones temporales tras %3 de:

%1" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumidos tras %3 de:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportar como..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostrar leyenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostrar el gráfico de coste total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostrar el gráfico de coste detallado" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagramas apilados:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrar al seleccionar" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reiniciar el filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Guardar %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" +"Imágenes rasterizadas (*.png *.jpg *.tiff);;Imágenes vectoriales (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "No se ha podido guardar la imagen en %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InicioFinDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tiempo%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumido%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Asignaciones%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Asignaciones temporales%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Muestra el consumo de memoria dinámica a lo largo del tiempo.
Pulse y " +"arrastre para seleccionar el intervalo de tiempo a filtrar.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Muestra el número de asignaciones de memoria a lo largo del tiempo." +"
Pulse y arrastre para seleccionar el intervalo de tiempo a filtrar.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Muestra el número de asignaciones temporales a lo largo del tiempo. Una " +"asignación temporal es la que está seguida inmediatamente por su " +"correspondiente liberación, sin otras asignaciones entre ambas.
Pulse y " +"arrastre para seleccionar el intervalo de tiempo a filtrar.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrado desde %2 hasta %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta filtrada)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Pulse y arrastre para seleccionar el intervalo de tiempo a filtrar." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consumido: %2. Pulse y arrastre para seleccionar el intervalo de " +"tiempo a filtrar." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Asignaciones: %2. Pulse y arrastre para seleccionar el intervalo de " +"tiempo a filtrar." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Asignaciones temporales: %2. Pulse y arrastre para seleccionar el " +"intervalo de tiempo a filtrar." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 asignaciones en total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 asignaciones temporales en total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 de picos consumo de memoria" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 de fugas en total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) asignaciones en %3 y por debajo." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) asignaciones temporales en %3 y por debajo." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contribución al consumo pico en %3 y por debajo." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) de fugas en %3 y por debajo." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pico de memoria" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostrar un gráfico de llamas sobre las contribuciones a los picos de consumo " +"de memoria dinámica de su aplicación." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostrar un gráfico de llamas sobre las fugas de memoria dinámica de su " +"aplicación. Una fuga de memoria se produce cuando no se libera." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostrar un gráfico de llamas sobre el número de asignaciones realizadas por " +"las funciones de su código." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostrar un gráfico de llamas sobre el número de asignaciones temporales " +"realizadas por las funciones de su código. Las asignaciones se marcan como " +"temporales cuando están inmediatamente seguidas por una liberación." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Seleccione la fuente de datos que se debe visualizar en el gráfico de llamas." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista de abajo a arriba" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Activar la vista del gráfico de llamas de abajo a arriba. Cuando esto no " +"está marcado, se activa por omisión la vista de arriba a abajo." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Contraer recursividad" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Contraer las estructuras de la pila de las funciones que se llaman a sí " +"mismas. Si esto no está marcado, las estructuras recursivas se visualizarán " +"de forma separada." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Umbral de coste:" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"El umbral de coste define un valor de corte fraccionario. Los elementos " +"con un coste relativo por debajo de este valor no se mostrarán en el gráfico " +"de llamas. Se trata de una optimización para poder generar rápidamente " +"gráficos de grandes conjuntos de datos con una sobrecarga pequeña de " +"memoria. Si necesita más detalle, disminuya el valor del umbral o defínalo " +"como cero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Buscar..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Buscar un símbolo en el gráfico de llamas." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Reiniciar la vista" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Vista llamador/llamado" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "generando gráfico de llamas..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% de un total de %3) asignaciones coinciden con la búsqueda." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% de un total de %3) coinciden con la búsqueda." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interfaz gráfica para Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un visualizador para archivos de datos de heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor original, encargado" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" +"Datos básicos de análisis de rendimiento con los que comparar otros archivos." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Cargar la lista de supresiones de fugas del archivo indicado. Especifique " +"una supresión por línea y empiece cada línea con «leak:» usando el formato " +"de archivo de supresiones LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorar las definiciones de supresiones integradas en el archivo de datos de " +"heaptrack. De forma predeterminada, heaptrack copiará las supresiones " +"definidas opcionalmente usando un símbolo `const char " +"*__lsan_default_suppressions()` en la aplicación que se está depurando. " +"Estas se aplican siempre que se analizan los datos, excepto cuando esta " +"función se desactiva explícitamente usando esta opción de la línea de " +"órdenes." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorar las definiciones de supresión que están integradas en heaptrack. De " +"forma predeterminada, heaptrack suprimirá ciertas fugas de memoria conocidas " +"en las bibliotecas comunes del sistema." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Archivos a cargar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[ARCHIVO...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 asignaciones de %2, con un total de %3 asignados con una media de %4 por " +"asignación." + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Tamaño de asignación solicitado" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Número de asignaciones" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Abrir archivo en el editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depurado:
%1 (adjunto)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depurado:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
tiempo de ejecución total:
%1, filtrado desde %2 hasta %3 " +"(%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
tiempo de ejecución total:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memoria total del sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
llamadas a funciones de asignación:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
asignaciones temporales:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
consumo pico de memoria dinámica:
%1 tras %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
pico RSS (incluyendo la sobrecarga de «heaptrack»):
%1" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta de consumo de memoria:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
fuga de memoria total:
%1 (%2 suprimidas)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
fuga de memoria total:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "El análisis del archivo %1 ha fallado." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumida" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Tamaños" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Los datos de entrada %1 no existen." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Los datos de entrada %1 no son un archivo." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Los datos de entrada %1 no se pueden leer." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "El análisis del archivo de supresiones ha fallado." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Desactivar las supresiones integradas" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Desactivar las supresiones integradas" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorar las definiciones de supresión que están integradas en heaptrack. De " +"forma predeterminada, heaptrack suprimirá ciertas fugas de memoria conocidas " +"de las bibliotecas comunes del sistema." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Cargando el archivo %1. Por favor, espere..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 comparado con %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Volviendo a analizar el archivo. Por favor, espere..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegación de código" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalizar..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automático (sin números de línea)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegación de código personalizada" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Indique la orden a usar para la navegación de código: «%f» se sustituirá con " +"el nombre de archivo, «%l» con el número de línea y «%c» con el número de " +"columna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Ventana principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Ruta a un archivo que contiene reglas de supresión de fugas en formato LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Abrir datos de Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Este campo indica el archivo de datos de heaptrack principal. Estos " +"archivos se llaman heaptrack.$APP.$PID.gz o heaptrack.$APP.$PID." +"zst. Puede generar estos archivos analizando el rendimiento de la " +"aplicación, por ejemplo, con:

\n" +"
heaptrack <aplicación> ...
\n" +"

O, de forma alternativa, puede adjuntar un proceso en ejecución usando:\n" +"

heaptrack --pid $(pidof <aplicación>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "ruta/a/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Opcionalmente, puede indicar un segundo archivo de datos de heaptrack " +"con el que comparar. Si se usa, este archivo se usará como base y sus costes " +"se restarán de los costes de los datos principales." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Datos de análisis de rendimiento:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Comparar con:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supresiones:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "ruta/a/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resumen" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Lista de funciones que asignan la mayor cantidad de memoria en un momento " +"determinado." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contribuciones pico" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lista de funciones que producen la mayor cantidad de fugas de memoria." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Mayores fugas de memoria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lista de funciones que asignan memoria más a menudo." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Mayor cantidad de asignaciones de memoria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Lista de funciones que realizan la mayor cantidad de asignaciones de memoria " +"temporal." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Mayor cantidad de asignaciones temporales" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supresiones" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "De abajo arriba" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrar por función..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrar por archivo..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrar por módulo..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Llamador / llamado" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "De arriba a abajo" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Gráfico de llamas" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Pilas" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Pila seleccionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Archivo" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Prefere&ncias" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtro" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "fusionando asignaciones... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "de 0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "de 9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "de 17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "de 33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "de 65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "de 129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "de 257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "de 512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "más de 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "reanálisis de datos" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "análisis de datos" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "Paso de %1: %2/%3 transcurrido: %4 restante: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "fusionando asignaciones..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "generando histograma de tamaños..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "generando gráficas..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Traza inversa" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"El número de veces que se ha llamado una función de asignación desde " +"esta ubicación." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"El número de asignaciones temporales. Estas asignaciones están seguidas " +"directamente por un espacio libre sin otras asignaciones entre ambos." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Las contribuciones de la posición indicada al consumo máximo de memoria " +"dinámica en bytes. Se tienen en cuenta las liberaciones de memoria " +"realizadas." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"La ubicación desde la que se ha llamado a una función de asignación. Es " +"posible que se desconozcan el símbolo de la función y la información del " +"archivo cuando falta la información de depuración al ejecutar «heaptrack»." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" en %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contribución pico: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "fugada: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "asignaciones: %1 (%2% del total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporales: %1 (%2% de las asignaciones, %3% del total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Traza inversa:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "llamada desde 1 ubicación" +msgstr[1] "llamada desde %1 ubicaciones" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% de un total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (self): %2
  %4% de un total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusive): %2
  %4% de un total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbolo: %1
binario: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 en %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 asignaciones de %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 en %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Símbolo" + +#~ msgid "Binary" +#~ msgstr "Binario" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "La función desde donde se ha llamado a una función de asignación. " +#~ "Puede estar sin resolver cuando falta la información de depuración." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "El módulo (es decir, el ejecutable o la biblioteca compartida) desde " +#~ "donde se ha llamado a una función de asignación." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "El nombre de la función del %1. Puede estar sin resolver cuando falta la " +#~ "información de depuración." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "El nombre del ejecutable en el que reside el símbolo." + +#~ msgid "Function" +#~ msgstr "Función" + +#~ msgid "Module" +#~ msgstr "Módulo" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "La función desde donde se ha llamado a una función de asignación. " +#~ "Puede ser desconocida cuando falta la información de depuración." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " en %2" + +#~ msgid "File" +#~ msgstr "Archivo" + +#~ msgid "Line" +#~ msgstr "Línea" + +#~ msgid "Allocated (Self)" +#~ msgstr "Asignada (propia)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Asignada (incl.)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "El archivo desde donde se ha llamado a la función de asignación. " +#~ "Puede estar vacío cuando falta la información de depuración." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "El número de línea desde donde se ha llamado a la función de " +#~ "asignación. Puede estar vacío cuando falta la información de depuración." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "La suma de todos los bytes asignados directamente desde esta " +#~ "ubicación, sin tener en cuenta las liberaciones." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "La suma de todos los bytes asignados incluidos desde esta ubicación, " +#~ "sin tener en cuenta las liberaciones." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " en %2:%3\n" +#~ " en %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "incluidas: asignada %1 sobre %2 llamadas (%3 temporales, es decir, %4%), " +#~ "pico en %5, fugada %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "propia: asignada %1 sobre %2 llamadas (%3 temporales, es decir, %4%), " +#~ "pico en %5, fugada %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Memoria asignada" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 asignaciones en total tras %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "%2 asignados tras %3 de:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Muestra la memoria total asignada a lo largo del tiempo. Este valor " +#~ "ignora las liberaciones y solo mide el rendimiento de la asignación de " +#~ "memoria dinámica." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) asignaciones en %3 y por debajo." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 contribución al consumo pico" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 asignaciones en total" + +#~ msgid "Allocated" +#~ msgstr "Asignada" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Mostrar un gráfico de llamas sobre la memoria total asignada por las " +#~ "funciones de su código. Aquí se suman todas las asignaciones de memoria " +#~ "sin tener en cuenta las liberaciones." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 asignaciones de %2 en %3:%4 en %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
total de bytes asignados (sin tener en cuenta liberaciones):
%1 (%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lista de funciones que asignan la mayor cantidad de memoria ignorando las " +#~ "liberaciones." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Mayor cantidad de memoria asignada" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "La suma de todos los bytes asignados desde esta ubicación, sin tener " +#~ "en cuenta las liberaciones." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "asignada: %1 (%2% del total)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Abrir archivo de salida de Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Archivos de datos de Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Gráficos" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "asignada %1 sobre %2 llamadas (%3 temporales, es decir, %4%), pico en %5, " +#~ "fugada %6" + +#~ msgid "debuggee: %1" +#~ msgstr "depurado: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "tiempo de ejecución total: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 en %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Asignaciones [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Asignaciones temporales [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Fugada [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Asignada [B]" + +#~ msgid "time in ms" +#~ msgstr "tiempo en ms" + +#~ msgid "memory heap size" +#~ msgstr "tamaño de la memoria dinámica" diff --git a/po/eu/heaptrack.po b/po/eu/heaptrack.po new file mode 100644 index 00000000..1b31ced7 --- /dev/null +++ b/po/eu/heaptrack.po @@ -0,0 +1,1254 @@ +# Translation for heaptrack.po to Euskara/Basque (eu). +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# KDE euskaratzeko proiektuko arduraduna . +# +# Translators: +# Iñigo Salvador Azurmendi , 2023. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-02-04 20:17+0100\n" +"Last-Translator: Iñigo Salvador Azurmendi \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 22.12.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Iñigo Salvador Azurmendi" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "xalba@ni.eus" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Kokalekua" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Esleipenak (Norbera)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Aldi baterako (Norbera)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Gailurra (Norbera)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Iragazi (Norbera)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, fuzzy, kde-format +msgid "Allocations (Incl.)" +msgstr "Esleipenak (" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, fuzzy, kde-format +msgid "Temporary (Incl.)" +msgstr "Aldi baterako (" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, fuzzy, kde-format +msgid "Peak (Incl.)" +msgstr "gailurra (" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, fuzzy, kde-format +msgid "Leaked (Incl.)" +msgstr "Iragazi (" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Esleipen funtzio bat deitu duen guraso-ikurra. Baliteke, arazteko " +"informazioa falta denean, funtzioaren izena ebatzi gabe gelditzea." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Esleipen-funtzio bat zuzenean kokaleku honetatik zenbat aldiz deitu zen." +"" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Deitzailea" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Deitua" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Gailurra" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Iragazi" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Esleipenak" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Aldi baterako" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"%1(e)ren kokalekua. Baliteke, arazteko informazioa falta denean, funtzioaren " +"izena ebatzi gabe gelditzea." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Esleipen-funtzio bat deitu duen sorburu-kodeko kokalekua. Ezezaguna izan " +"daiteke arazteko informazioa falta denean." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Memoria esleipenak" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Erabilitako memoria" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Aldi baterako esleipenak" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Igarotako denbora" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Memoria esleipenen guztizkoa" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Memoriaren erabilera guztira" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Aldi baterako esleipenak guztira" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 byte)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Esportatu honela..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Erakutsi legenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Erakutsi kostu osoaren grafikoa" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Kostuen grafiko zehatza erakutsi" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Pilatutako diagramak:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Berrezarri iragazkia" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Gorde %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Raster irudia (*.png *.jpg *.tiff);;Bektore irudia (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Irudia %1(e)an gordetzea huts egin du." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "HasieraBukaeraDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Denbora%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Erabilita%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Esleipenak%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Aldi baterako esleipenak%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Denboran zehar memoria dinamikoaren («heap») erabilera erakusten du." +"
Egin klik eta arrastatu iragazteko denbora-tarte bat hautatzeko.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Denboran zehar memoria esleipenen kopurua erakusten du.
Egin klik eta " +"arrastatu iragazteko denbora-tarte bat hautatzeko.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (%2(e)tik %3 arte iragazita, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (iragazitako delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Egin klik eta arrastatu iragazteko denbora-tarte bat hautatzeko." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Erabilita: %2. Egin klik eta arrastatu iragazteko denbora-tarte bat " +"hautatzeko." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Esleipenak: %2. Egin klik eta arrastatu iragazteko denbora-tarte bat " +"hautatzeko." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Aldi baterako Esleipenak: %2. Egin klik eta arrastatu iragazteko " +"denbora-tarte bat hautatzeko." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 esleipen guztira" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 aldi baterako esleipen guztira" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 gailur memoria erabilera" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 iragazi dira guztira" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%%2) esleipen %3(e)an eta azpian." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%%2) aldi baterako esleipen %3(e)an eta azpian." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%%2) iragazita %3(e)an eta azpian." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Memoria gailurra" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Behetik-gorako ikuspegia" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Kostu-atalasea:" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Bilatu..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Berrezarri ikuspegia" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Deitzailea/Deitua ikuspegia" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "sugar-grafikoa sortzen..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack GUI" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "«Heaptrack» datu-fitxategi irudikatzaile bat." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Jatorrizko egilea, mantentzailea" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" +"Oinarrizko profilaren datuak, beste fitxategi batzuk hauekin alderatzeko." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Zamatu beharreko fitxategiak" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FITXATEGIA...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Fitxategiak ez du sintaxi azterketa gainditu: %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Erabilita" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Neurriak" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "%1 fitxategia zamatzen, itxoin mesedez..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Kodea nabigatzea" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Neurrira..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatikoa (Lerro zenbakirik gabe)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Leiho-nagusia" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Ireki «Headtrack» datuak" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Laburpena" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Denbora jakin batean memoria gehien esleitu duten funtzioen zerrenda." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Memoria gehien iragazten duten funtzioen zerrenda." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Memoria iragazte handienak" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Behetik-gora" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "iragazi funtzioaren arabera..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "iragazi fitxategiaren arabera..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "iragazi moduluaren arabera..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Deitzailea / Deitua" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Goiti-behera" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Pilak" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Hautatutako pila:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Fitxategia" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Ezarpe&nak" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Iragazkia" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "esleipenak bateratzen... %%1" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "guztira" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B -> 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B -> 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B -> 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B -> 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B -> 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B -> 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B -> 512KB" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B -> 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "1KB baino gehiago" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "datuak sintaktikoki aztertzen" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "esleipenak bateratzen..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "neurrien histograma eraikitzen..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "diagramak sortzen..." + +#: gui/stacksmodel.cpp:99 +#, fuzzy, kde-format +msgid "Backtrace" +msgstr "Atzera-arrastoa" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Esleipen-funtzio bat kokaleku honetatik zenbat aldiz deitu den." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "iragazi: %1 (guztizkoaren %%2)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "esleipenak: %1 (guztizkoaren %%2)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "aldi baterako: %1 (esleipenen %%2, guztizkoaren %%3)\n" + +#: gui/treemodel.cpp:168 +#, fuzzy, kde-format +msgid "backtrace:" +msgstr "Atzera-arrastoa" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "kokaleku batetik deitua" +msgstr[1] "%1 kokalekutatik deitua" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "ikurra: %1
bitarra: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 %2(e)an" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/fr/heaptrack.po b/po/fr/heaptrack.po new file mode 100644 index 00000000..f10d9e8b --- /dev/null +++ b/po/fr/heaptrack.po @@ -0,0 +1,1635 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Vincent Pinon , 2015. +# SPDX-FileCopyrightText: 2020, 2021, 2022, 2023 Xavier Besnard +# Xavier BESNARD , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-10-11 21:05+0200\n" +"Last-Translator: Xavier BESNARD \n" +"Language-Team: fr\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 23.08.1\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vincent Pinon, Xavier Besnard" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "vpinon@kde.org, xavier.besnard@neuf.fr" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Emplacement" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allocations (Automatique)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporaire (Automatique)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pic (automatique)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Fuite (Automatique)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allocations (Inclus)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporaire (Inclus)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pic (Inclus)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Fuite (Inclus)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"La fonction parente qui a appelé une fonction d'allocation. Le nom de la " +"fonction peut être non résolu quand les informations de débogage sont " +"absentes." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Le nombre de fois que la fonction d'allocation a été appelée depuis cet " +"emplacement." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Le nombre d'allocations temporaires. Ces allocations sont directement " +"suivies par leur désallocation, sans aucune autre allocation entre." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"La mémoire maximale du tas local, en octets, consommée par des " +"allocations venant directement de cet emplacement. Ceci prend en compte les " +"libérations." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Les octets alloués directement à cet emplacement qui n'ont pas été " +"libérés." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Le nombre de fois que la fonction d'allocation a été appelée depuis cet " +"emplacement ou toute fonction appelée à partir d'ici." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Le nombre d'allocations temporaires. Ces allocations sont directement " +"suivies par leur désallocation, sans aucune autre allocation entre." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"La mémoire maximale en octets du tas local inclus et consommé par des " +"allocations provenant de cet emplacement pour des fonctions appelés ici. " +"Ceci prend en compte les désallocations." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Les octets alloués à cet emplacement qui n'ont pas été libérés." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Fonction appelante" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Fonction appelée" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pic" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Fuite" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Allocations" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporaire" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"L'emplacement de %1. Le nom de fonction peut être non résolu quand les " +"informations de débogage sont manquantes." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"L'emplacement du code dans la source ayant appelé une fonction " +"d'allocation. Peut être non résolu quand les informations de débogage sont " +"manquantes." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Allocations mémoire" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Mémoire consommée" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Allocations temporaires" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Temps écoulé" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total des allocations de mémoire" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total des consommations de mémoire" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total des allocations temporaires" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 octets)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "Total de %1 allocations après %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "Total de %1 allocations temporaires après %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "Total de %1 consommé après %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 allocations après %3 à partir :

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 allocations temporaires après %3 à partir de :

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" +"%2 consommé après %3 à partir de :

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exporter sous..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Afficher une légende" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Afficher un graphique de coût total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Afficher un graphique de coût détaillé" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagrammes empilés :" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrer selon la sélection..." + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Réinitialiser le filtre" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Enregistrer %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Image matricielle (*.png *.jpg *.tiff) ; Image vectorielle (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Impossible d'enregistrer l'image vers %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "DébutFinDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Temps%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consommé%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Allocations%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Allocations temporaires%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +" Affiche la consommation de mémoire dans le tas local dans le temps." +"
Cliquez et faites glisser pour sélectionner un intervalle de temps pour " +"le filtrage.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Affiche le nombre d'allocations de mémoire durant la période de temps." +"
Cliquez et faites glisser pour sélectionner un intervalle de temps pour " +"le filtrage.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Affiche le nombre d'allocations temporaires de mémoire sur une période " +"donnée. Une allocation temporaire est celle qui est suivie directement par " +"sa désallocation, sans autre allocation réalisée entre les deux.
Cliquez " +"et faites glisser pour sélectionner l'intervalle de temps pour le filtrage." + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (Filtré à partir de %2 à %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (données filtrées)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Cliquez et faites glisser pour sélectionner l'intervalle de temps pour le " +"filtrage." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consommé : %2. Cliquez et faites glisser pour sélectionner " +"l'intervalle de temps pour le filtrage." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Allocations : %2. Cliquez et faites glisser pour sélectionner " +"l'intervalle de temps pour le filtrage." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Allocations temporaires : %2. Cliquez et faites glisser pour " +"sélectionner l'intervalle de temps pour le filtrage." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "Total de %1 allocations" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "Total des %1 allocations temporaires" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "Consommation de mémoire du pic %1" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "Total de %1 en fuite" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2 %) allocations dans %3 et ci-dessous." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2 %) allocations temporaires dans %3 et ci-dessous." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2 %) contribution à la consommation du pic pour %3 et en dessous." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) en fuite dans %3 et ci-dessous." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pic de mémoire" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Afficher un graphique en flammes concernant les contributions au pic de " +"consommation mémoire pour le tas local." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Afficher un graphique en flammes concernant les contributions au pic de " +"consommation mémoire pour le tas local. La mémoire est considérée comme une " +"fuite quand elle n'est jamais désallouée." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Afficher un graphique en flammes concernant le nombre d'allocations " +"demandées par les fonctions de votre code." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Afficher un graphique en flammes concernant le nombre d'allocations " +"demandées par les fonctions de votre code. Les allocations sont marquées " +"comme temporaires quand elles sont immédiatement suivies par une " +"désallocation." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Sélectionner la source de données à afficher dans un graphe en flammes." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Affichage de bas en haut" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Active l'affichage d'un graphique en flammes de bas en haut. Quand cette " +"option est désactivée, l'affichage du haut vers le base est activé par " +"défaut." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Réduite la récursion" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Éliminer les structures de pile pour les fonctions s'appelant elles-même. " +"Lorsque cette option est activée, les structures récursives seront affichées " +"séparément." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Seuil de coût :" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +" Le seuil de coût définit une valeur fractionnaire de coupure. Les " +"éléments avec un coût relatif sous cette valeur ne seront pas affichés dans " +"le graphique en flammes. Ceci est fait comme une optimisation pour générer " +"rapidement des graphiques avec des ensembles de données importants avec peu " +"de consommation de mémoire. Si vous avez besoin de plus de détails, diminuer " +"la valeur du seuil ou régler le à zéro." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Chercher…" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Rechercher un symbole dans le graphique en flammes." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Remettre l'affichage à zéro" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Affichage des Appelant / Appelé" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "Génération du graphique en flammes..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (Total de %2 % parmi %3) allocations correspondant à la recherche." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (Total %2 % de %3) correspondant à la recherche." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interface pour Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un afficheur de fichiers de données « Heaptrack »." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Auteur initial, mainteneur" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Les données de base du profil à comparer aux autres fichiers." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Charger la lises des suppressions de fuite à partir du fichier spécifié. " +"Veuillez spécifier une suppression par ligne et démarrer chaque ligne par " +"« leak », c'est-à-dire en utilisant le format de fichier de suppression " +"« LSAN »." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorer les définitions de suppression qui sont intégrées dans le fichier de " +"données « Heaptrack ». Par défaut, heaptrack copiera les suppressions " +"définies optionnellement grâce à un symbole « const char " +"*__lsan_default_suppressions() » dans l'application en cours de débogage. " +"Celles-ci sont alors toujours appliquées lors de l'analyse des données, sauf " +"si cette fonctionnalité est explicitement désactivée en utilisant cette " +"option de ligne de commandes." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorer les définitions de suppression intégrées dans heaptrack. Par défaut, " +"Heaptrack supprimera certaines fuites connues des bibliothèques communes du " +"système." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Fichiers à charger" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FICHIER...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 allocations parmi %2, totalisant %3 alloués avec une moyenne de %4 par " +"allocation" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Taille de l'allocation demandée" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Nombre d'allocations" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Ouvrir le fichier dans l'éditeur" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
Sujet de débogage :
%1 " +"(attaché)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
débogueur :
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
Total du temps d'exécution :
%1 filtré à partir de %2 à " +"%3 (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
Total du temps d'exécution :
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
Mémoire totale du système :
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" +"
Appels aux fonctions d'allocation :
%1 (%2 / s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
Allocations temporaires :
%1 (%2%, %3 / s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
Consommation de mémoire du pic sur le tas local :
%1 " +"après %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
Pic « RSS » (Y compris le surplus du tas local) :
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
Delta de consommation de mémoire :
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
Total des fuites mémoire :
%1 (%2 supprimé)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
Total des fuites mémoire :
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Impossible d'analyser le fichier %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consommé" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Tailles" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "La donnée d'entrée %1 n'existe pas." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "La donné d'entrées %1 n'est pas un fichier." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "La donné d'entrée %1 est non lisible." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Impossible d'analyser le fichier de suppression." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Désactiver les suppressions intégrées" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Désactiver les suppressions intégrées" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorer les définitions de suppression intégrées dans Heaptrack. Par défaut, " +"Heaptrack supprimera certaines fuites connues des bibliothèques communes du " +"système." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Chargement du fichier %1, veuillez patienter..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "« Heaptrack» - Comparaison de %1 avec %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Nouvelle analyse du fichier, veuillez patienter..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navigation dans le code" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personnaliser..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatique (Aucun numéro de lignes)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navigation personnalisée dans le code" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Spécifier la commande à utiliser pour la navigation dans le code. Les " +"éléments « %f », « %l » et « %c » seront respectivement remplacés par le nom " +"du fichier, le numéro de ligne et le numéro de colonne." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Fenêtre principale" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Emplacement du fichier contenant les règles de suppression de fuites dans le " +"format « LSAN »." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Ouvrir des fichiers « Heaptrack »" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Ce champ spécifie le fichier primaire pour les données des traces " +"pour le tas local. Ces fichiers sont appelés heaptrack.$APP.$PID.gz " +"ou heaptrack.$APP.$PID.zst. Vous pouvez réaliser un tel fichier en " +"caractérisant votre application, par exemple, grâce à :

\n" +"
 « heaptrack <votre_application>... » 
\n" +"

Ou, de façon alternative, vous pouvez l'associer à un processus en " +"exécution grâce à :

\n" +"
 « heaptrack --pid $(PID_de <votre_application>)"
+
+#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile)
+#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo)
+#: gui/mainwindow.ui:75 gui/mainwindow.ui:88
+#, kde-format
+msgid "path/to/heaptrack.$APP.$PID.{gz,zst}"
+msgstr "emplacement / vers / heaptrack.$APP.$PID.{gz,zst}"
+
+#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo)
+#: gui/mainwindow.ui:85
+#, kde-format
+msgid ""
+"You can optionally specify a second heaptrack data file to compare to. "
+"If set, this file will be used as a base and its cost gets subtracted from "
+"the primary data costs."
+msgstr ""
+" Vous pouvez spécifier de façon optionnelle un second fichier de données "
+"« heaptrack » pour faire des comparaisons. Si cette option est activée, ce "
+"fichier sera utilisé comme une référence. Son coût est soustrait des coûts "
+"des données primaires."
+
+#. i18n: ectx: property (text), widget (QLabel, openFileLabel)
+#: gui/mainwindow.ui:98
+#, kde-format
+msgid "Profile &Data:"
+msgstr "&Données du profil :"
+
+#. i18n: ectx: property (text), widget (QLabel, compareToLabel)
+#: gui/mainwindow.ui:108
+#, kde-format
+msgid "Compare to:"
+msgstr "Comparer à :"
+
+#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel)
+#: gui/mainwindow.ui:121
+#, kde-format
+msgid "Suppressions:"
+msgstr "Suppressions :"
+
+#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions)
+#: gui/mainwindow.ui:131
+#, kde-format
+msgid "path/to/lsan_suppressions.txt"
+msgstr "emplacement/vers/lsan_suppressions.txt"
+
+#. i18n: ectx: attribute (title), widget (QWidget, summaryTab)
+#: gui/mainwindow.ui:244
+#, kde-format
+msgid "Summary"
+msgstr "Résumé"
+
+#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel)
+#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak)
+#: gui/mainwindow.ui:345 gui/mainwindow.ui:358
+#, kde-format
+msgid "List of functions that allocated the most memory at a given time."
+msgstr "Liste des fonctions allouant le plus de la mémoire à un moment donné."
+
+#. i18n: ectx: property (text), widget (QLabel, topPeakLabel)
+#: gui/mainwindow.ui:348
+#, kde-format
+msgid "Peak Contributions"
+msgstr "Contributions au pic"
+
+#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel)
+#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked)
+#: gui/mainwindow.ui:384 gui/mainwindow.ui:397
+#, kde-format
+msgid "List of functions that leak the most memory."
+msgstr "Liste des fonctions ayant les plus importantes fuites de mémoire."
+
+#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel)
+#: gui/mainwindow.ui:387
+#, kde-format
+msgid "Largest Memory Leaks"
+msgstr "Fuites de mémoire les plus importantes"
+
+#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel)
+#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations)
+#: gui/mainwindow.ui:423 gui/mainwindow.ui:436
+#, kde-format
+msgid "List of functions that allocate memory most often."
+msgstr "Liste des fonctions allouant le plus souvent de la mémoire."
+
+#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel)
+#: gui/mainwindow.ui:426
+#, kde-format
+msgid "Most Memory Allocations"
+msgstr "La plupart des allocations de mémoire"
+
+#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel)
+#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary)
+#: gui/mainwindow.ui:465 gui/mainwindow.ui:478
+#, kde-format
+msgid "List of functions that produced the most temporary memory allocations."
+msgstr ""
+"Liste des fonctions effectuant les allocations de mémoire les plus "
+"temporaires."
+
+#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel)
+#: gui/mainwindow.ui:468
+#, kde-format
+msgid "Most Temporary Allocations"
+msgstr "Allocations de mémoire les plus temporaires"
+
+#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox)
+#: gui/mainwindow.ui:501
+#, kde-format
+msgid "Suppressions"
+msgstr "Suppressions"
+
+#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab)
+#: gui/mainwindow.ui:533
+#, kde-format
+msgid "Bottom-Up"
+msgstr "De bas en haut"
+
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction)
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction)
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction)
+#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746
+#, kde-format
+msgid "filter by function..."
+msgstr "Filtrer par fonction..."
+
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile)
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile)
+#: gui/mainwindow.ui:564 gui/mainwindow.ui:753
+#, kde-format
+msgid "filter by file..."
+msgstr "Filtrer par fichier..."
+
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule)
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule)
+#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule)
+#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760
+#, kde-format
+msgid "filter by module..."
+msgstr "Filtrer par module..."
+
+#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab)
+#: gui/mainwindow.ui:601
+#, kde-format
+msgid "Caller / Callee"
+msgstr "Appelant / Appelé"
+
+#. i18n: ectx: attribute (title), widget (QWidget, topDownTab)
+#: gui/mainwindow.ui:725
+#, kde-format
+msgid "Top-Down"
+msgstr "De haut en bas"
+
+#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab)
+#: gui/mainwindow.ui:790
+#, kde-format
+msgid "Flame Graph"
+msgstr "Graphique en flammes"
+
+#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock)
+#: gui/mainwindow.ui:806
+#, kde-format
+msgid "S&tacks"
+msgstr "Pi&les"
+
+#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel)
+#: gui/mainwindow.ui:831
+#, kde-format
+msgid "Selected Stack:"
+msgstr "Pile sélectionnée :"
+
+#. i18n: ectx: property (title), widget (QMenu, menu_File)
+#: gui/mainwindow.ui:868
+#, kde-format
+msgid "&File"
+msgstr "&Fichier"
+
+#. i18n: ectx: property (title), widget (QMenu, menu_Settings)
+#: gui/mainwindow.ui:873
+#, kde-format
+msgid "Setti&ngs"
+msgstr "Para&mètres"
+
+#. i18n: ectx: property (title), widget (QMenu, menuFilter)
+#: gui/mainwindow.ui:878
+#, kde-format
+msgid "Filter"
+msgstr "Filtre"
+
+#: gui/parser.cpp:387
+#, kde-format
+msgid "merging allocations... %1%"
+msgstr "Fusion des allocations %1 %..."
+
+#: gui/parser.cpp:557
+#, kde-format
+msgid "total"
+msgstr "total"
+
+#: gui/parser.cpp:559
+#, kde-format
+msgid "0B to 8B"
+msgstr "0B à 8B"
+
+#: gui/parser.cpp:560
+#, kde-format
+msgid "9B to 16B"
+msgstr "9B à 16B"
+
+#: gui/parser.cpp:561
+#, kde-format
+msgid "17B to 32B"
+msgstr "17B à 32B"
+
+#: gui/parser.cpp:562
+#, kde-format
+msgid "33B to 64B"
+msgstr "33B à 64B"
+
+#: gui/parser.cpp:563
+#, kde-format
+msgid "65B to 128B"
+msgstr "65B à 128B"
+
+#: gui/parser.cpp:564
+#, kde-format
+msgid "129B to 256B"
+msgstr "129B à 256B"
+
+#: gui/parser.cpp:565
+#, kde-format
+msgid "257B to 512B"
+msgstr "257B à 512B"
+
+#: gui/parser.cpp:566
+#, kde-format
+msgid "512B to 1KB"
+msgstr "512 o à 1Ko"
+
+#: gui/parser.cpp:567
+#, kde-format
+msgid "more than 1KB"
+msgstr "plus de 1Ko"
+
+#: gui/parser.cpp:645
+#, kde-format
+msgid "reparsing data"
+msgstr "Nouvelle analyse des données"
+
+#: gui/parser.cpp:645
+#, kde-format
+msgid "parsing data"
+msgstr "Analyse des données"
+
+#: gui/parser.cpp:659
+#, kde-format
+msgid "%1 pass: %2/%3  spent: %4  remaining: %5"
+msgstr "%1 passe : %2 / %3 consommé : %4 restant : %5"
+
+#: gui/parser.cpp:715
+#, kde-format
+msgid "merging allocations..."
+msgstr "Fusion des allocations"
+
+#: gui/parser.cpp:726
+#, kde-format
+msgid "building size histogram..."
+msgstr "Construction de l'histogramme de taille..."
+
+#: gui/parser.cpp:739
+#, kde-format
+msgid "building charts..."
+msgstr "Construction des graphiques..."
+
+#: gui/stacksmodel.cpp:99
+#, kde-format
+msgid "Backtrace"
+msgstr "Pile d'appels"
+
+#: gui/treemodel.cpp:80
+#, kde-format
+msgid ""
+"The number of times an allocation function was called from this location."
+""
+msgstr ""
+"Le nombre de fois fonction d'allocation a été appelée depuis cet "
+"emplacement."
+
+#: gui/treemodel.cpp:83
+#, kde-format
+msgid ""
+"The number of temporary allocations. These allocations are directly "
+"followed by a free without any other allocations in-between."
+msgstr ""
+"Le nombre d'allocations temporaires. Ces allocations sont directement "
+"suivies par leur désallocation, sans aucune autre allocation entre."
+
+#: gui/treemodel.cpp:87
+#, kde-format
+msgid ""
+"The contributions from a given location to the maximum heap memory "
+"consumption in bytes. This takes deallocations into account."
+msgstr ""
+"Les contributions à partir d'un emplacement donné à la consommation en "
+"octets de la mémoire maximale du tas local. Ceci prend en compte les "
+"libérations."
+
+#: gui/treemodel.cpp:94
+#, kde-format
+msgid ""
+"The location from which an allocation function was called. Function "
+"symbol and file information may be unknown when debug information was "
+"missing when heaptrack was run."
+msgstr ""
+"L'emplacement depuis lequel une fonction d'allocation a été annulée. Les "
+"informations de symbole de fonction et de fichier peuvent être inconnues "
+"quand les informations de débogage n'étaient pas disponibles quand Heaptrack "
+"a été exécuté."
+
+#: gui/treemodel.cpp:149 gui/treemodel.cpp:173
+#, kde-format
+msgctxt "1: function, 2: module, 3: module path"
+msgid ""
+"%1\n"
+"  in %2 (%3)"
+msgstr ""
+"%1\n"
+" dans %2 (%3)"
+
+#: gui/treemodel.cpp:159
+#, kde-format
+msgid "peak contribution: %1 (%2% of total)\n"
+msgstr "Contribution au pic : %1 (Total de %2 %)\n"
+
+#: gui/treemodel.cpp:160
+#, kde-format
+msgid "leaked: %1 (%2% of total)\n"
+msgstr "Fuite : %1 (total de %2%)\n"
+
+#: gui/treemodel.cpp:161
+#, kde-format
+msgid "allocations: %1 (%2% of total)\n"
+msgstr "Allocations : %1 (Total de %2%)\n"
+
+#: gui/treemodel.cpp:162
+#, kde-format
+msgid "temporary: %1 (%2% of allocations, %3% of total)\n"
+msgstr "Temporaire : %1 (%2 % des allocations, total de %3 %)\n"
+
+#: gui/treemodel.cpp:168
+#, kde-format
+msgid "backtrace:"
+msgstr "Pile d'appels :"
+
+#: gui/treemodel.cpp:180
+#, kde-format
+msgid "called from one location"
+msgid_plural "called from %1 locations"
+msgstr[0] "appelé depuis un emplacement"
+msgstr[1] "appelé depuis %1 emplacements"
+
+#: gui/util.cpp:32
+#, kde-format
+msgid "??"
+msgstr " ??"
+
+#: gui/util.cpp:108
+#, kde-format
+msgid "%1: %2
  %4% out of %3 total" +msgstr "%1 : %2
  Total de %4% parmi %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (automatique) : %2
  Total de %4 % parmi %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclus) : %2
  Total de %4% parmi %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "Symbole : %1
Binaire : %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 dans %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 allocations à partir de %2" + +#, fuzzy +#~| msgid "%1 in %2 (%3)" +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 de %2 (%3)" + +#, fuzzy +#~| msgid "%1 in %2 (%3)" +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 de %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbole" + +#~ msgid "Binary" +#~ msgstr "Binaire" + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "La fonction parente qui a appelé une fonction d'allocation. Peut être " +#~ "inconnue quand les informations de débogage ne sont pas disponibles." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Le module, c'est à dire l'exécutable ou la librarie partagée, depuis " +#~ "lequel une fonction d'allocation a été appelée." + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "La fonction parente qui a appelé une fonction d'allocation. Peut être " +#~ "inconnue quand les informations de débogage ne sont pas disponibles." + +#~ msgid "Function" +#~ msgstr "Fonction" + +#~ msgid "Module" +#~ msgstr "Module" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "La fonction parente qui a appelé une fonction d'allocation. Peut être " +#~ "inconnue quand les informations de débogage ne sont pas disponibles." + +#, fuzzy +#~| msgid "%1 in %2 (%3)" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "%1 de %2 (%3)" + +#~ msgid "File" +#~ msgstr "Fichier" + +#~ msgid "Line" +#~ msgstr "Ligne" + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Self)" +#~ msgstr "Alloué" + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Incl.)" +#~ msgstr "Alloué" + +#, fuzzy +#~| msgid "" +#~| "The file and line number where the allocation function was called " +#~| "from. May be empty when debug information is missing." +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Le fichier et numéro de ligne d'où la fonction d'allocation a été " +#~ "appelée. Peut être vide si les information de débogage ne sont pas " +#~ "disponibles." + +#, fuzzy +#~| msgid "" +#~| "The file and line number where the allocation function was called " +#~| "from. May be empty when debug information is missing." +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Le fichier et numéro de ligne d'où la fonction d'allocation a été " +#~ "appelée. Peut être vide si les information de débogage ne sont pas " +#~ "disponibles." + +#, fuzzy +#~| msgid "" +#~| "The sum of all bytes allocated from this location, ignoring " +#~| "deallocations." +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "La somme de tous les octets alloués depuis cet emplacement, en " +#~ "ignorant les libérations." + +#, fuzzy +#~| msgid "" +#~| "The sum of all bytes allocated from this location, ignoring " +#~| "deallocations." +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "La somme de tous les octets alloués depuis cet emplacement, en " +#~ "ignorant les libérations." + +#, fuzzy +#~| msgctxt "1: function, 2: file, 3: module" +#~| msgid "" +#~| "%1\n" +#~| " at %2\n" +#~| " in %3" +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " à %2\n" +#~ " de %3" + +#, fuzzy +#~| msgid "allocated %1 over %2 calls, peak at %3, leaked %4" +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "%1 alloués sur %2 appels, pic à %3, %4 de fuite" + +#, fuzzy +#~| msgid "allocated %1 over %2 calls, peak at %3, leaked %4" +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "%1 alloués sur %2 appels, pic à %3, %4 de fuite" + +#~ msgid "Memory Allocated" +#~ msgstr "Mémoire allouée" + +#, fuzzy +#~| msgid "Memory Allocations" +#~ msgid "%1 allocated in total after %2" +#~ msgstr "Allocations mémoire" + +#, fuzzy +#~| msgid "Memory Allocations" +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "Allocations mémoire" + +#, fuzzy +#~| msgid "Memory Allocations" +#~ msgid "%1 allocated in total" +#~ msgstr "Allocations mémoire" + +#~ msgid "Allocated" +#~ msgstr "Alloué" + +#, fuzzy +#~| msgid "" +#~| "bytes allocated in total (ignoring deallocations): %1 " +#~| "(%2/s)" +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "octets alloués au total (ignorant les libérations): %1 " +#~ "(%2/s)" + +#, fuzzy +#~| msgid "Memory Allocated" +#~ msgid "Most Memory Allocated" +#~ msgstr "Mémoire allouée" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "La somme de tous les octets alloués depuis cet emplacement, en " +#~ "ignorant les libérations." + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Ouvrir un fichier de sortie Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Fichiers de données heaptrack (heaptrack.*)" + +#, fuzzy +#~| msgid "allocated %1 over %2 calls, peak at %3, leaked %4" +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "%1 alloués sur %2 appels, pic à %3, %4 de fuite" + +#~ msgid "debuggee: %1" +#~ msgstr "debuggee : %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "temps d'exécution total : %1s" + +#~ msgid "Allocations [-]" +#~ msgstr "Allocations [-]" + +#, fuzzy +#~| msgid "Memory Allocations" +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Allocations mémoire" + +#~ msgid "Leaked [B]" +#~ msgstr "Fuite [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Alloué [B]" + +#~ msgid "time in ms" +#~ msgstr "temps en ms" + +#~ msgid "memory heap size" +#~ msgstr "taille mémoire du tas" diff --git a/po/gl/heaptrack.po b/po/gl/heaptrack.po new file mode 100644 index 00000000..90134f7f --- /dev/null +++ b/po/gl/heaptrack.po @@ -0,0 +1,1606 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Adrián Chaves Fernández (Gallaecio) , 2015, 2016, 2017. +# Adrián Chaves (Gallaecio) , 2017, 2018, 2019, 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-06-07 10:42+0200\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Adrian Chaves (Gallaecio)" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "adrian@chaves.io" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Lugar" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Asignacións (directas)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporais (directas)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pico (directo)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Perdida (directa)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Asignacións (totais)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporais (totais)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pico (total)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Perdida (total)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"O símbolo superior que chamou a unha función de asignación. O nome da " +"función pode que non se resolva se falta a información de depuración." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"O número de veces que se chamou directamente a unha función de " +"asignación desde aquí." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"O número de asignacións temporais directas. Estas asignacións van " +"seguidas directamente por unha liberación sen outras asignacións entre " +"medias." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"O número máximo de memoria dinámica (heap) en bytes consumidos por todas " +"as asignacións realizadas directamente desde aquí. Isto ten en conta " +"liberacións." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "Os bytes asignados directamente aquí que non se liberaron." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"O número total de veces que se chamou a unha función de asignación desde " +"aquí ou desde funcións chamadas desde aquí." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"O número total de asignacións temporais. Estas asignacións van seguidas " +"directamente por unha liberación sen outras asignacións entre medias." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"O número máximo total de memoria dinámica (heap) en bytes consumidos por " +"todas as asignacións realizadas desde aquí ou desde funcións chamadas desde " +"aquí. Isto ten en conta liberacións." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Os bytes asignados aquí que non se liberaron." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Chamador" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Chamado" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pico" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Perdida" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Asignacións" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporal" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"O lugar onde está %1. O nome da función pode que non se resolva se falta a " +"información de depuración." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"O lugar do código fonte desde o que se chamou a unha función de " +"asignación. Pode que se descoñeza se falta a información de depuración." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Asignacións de memoria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memoria consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Asignacións temporais" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tempo transcorrido" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Asignacións totais de memoria" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Consumo total de memoria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Asignacións temporais totais" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 asignacións en total despois de %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 asignacións temporais en total despois de %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumidos en total despois de %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 asignacións despois de %3 desde:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 asignacións temporais despois de %3 desde:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" +"%2 consumidas despois de %3 desde:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportar como…" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Amosar a lenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Amosar o gráfico de custe total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Amosar o gráfico de custe total" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagramas acumulativos" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrar a selección" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Restaurar o filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Gardar %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Mapa de bits (*.png *.jpg *.tiff);;Imaxe vectorial (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Non foi posíbel gardar a imaxe en «%1»." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InicioFinDiferenza" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tempo%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumo%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Asignacións%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Asignacións temporais%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Amosar o consumo de memoria dinámica no tempo.
Prema e arrastre para " +"seleccionar un intervalo de tempo polo que filtrar.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra o número de asignacións de memoria no tempo.
Prema e arrastre " +"para seleccionar un intervalo de tempo polo que filtrar.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra o número de asignacións de memoria temporais no tempo. Estas " +"asignacións van seguidas directamente por unha liberación, sen que se " +"produzan outras asignacións entre medias.
Prema e arrastre para " +"seleccionar un intervalo de tempo polo que filtrar.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrado de %2 a %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (diferenza filtrada)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Prema e arrastre para seleccionar un intervalo de tempo polo que filtrar." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, consumo: %2. Prema e arrastre para seleccionar un intervalo de tempo " +"polo que filtrar." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, asignacións: %2. Prema e arrastre para seleccionar un intervalo de " +"tempo polo que filtrar." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, asignacións temporais: %2. Prema e arrastre para seleccionar un " +"intervalo de tempo polo que filtrar." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 asignacións en total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 asignacións temporais en total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 de pico de consumo de memoria" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 perdido en total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) asignacións en %3 e por debaixo." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) asignacións temporais en %3 e por debaixo." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "Contribución de %1 (%2%) ao pico de consumo en %3 e por debaixo." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) perdido en %3 e por debaixo." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pico de memoria" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Amosar un gráfico de chamas coas contribucións ao pico de consumo de memoria " +"dinámica (heap) da aplicación." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Amosar un gráfico de chamas coa memoria dinámica (heap) perdida pola " +"aplicación. A memoria considérase perdida cando nunca se libera." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Amosar un gráfico de chamas co número de asignacións realizadas por funcións " +"do seu código." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Amosar un gráfico de chamas co número de asignacións temporais realizadas " +"por funcións do seu código. As asignacións márcanse como temporais cando van " +"seguidas inmediatamente pola súa liberación." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Seleccionar a fonte de datos para visualizar no gráfico de chamas." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista de abaixo a arriba" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Activar a vista de abaixo a arriba do gráfico de chamas. Se non marca esta " +"opción, actívase a vista de arriba a abaixo de maneira predeterminada." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Pregar a recursividade" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Pregar as estruturas da rima para as funcións que se chamen a si mesmas. Se " +"desmarca esta opción, as estruturas recursivas visualizaranse por separado." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Límite de custo: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"O límite de custo define unha fracción para usar como valor de corte. Os " +"elementos cun custo relativo inferior ao valor indicado non se amosan no " +"gráfico de chamas. Isto faise por motivos de rendemento, para poder xerar " +"rapidamente gráficos para grandes conxuntos de datos sen consumir demasiada " +"memoria. Se quere máis detalles, reduza o valor límite, ou póñao a cero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Buscar…" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Buscar un símbolo no gráfico de chamas." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Restaurar a vista" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Ver o chamador e o chamado" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "Xerando o gráfico de chamas…" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% dun total de %3) asignacións que coinciden coa busca." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% dun total de %3) que coinciden coa busca." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interface gráfica de Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un visor de ficheiros de datos de Heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "© 2015 Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor orixinal e mantedor." + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Datos básicos de perfil cos que comparar outros ficheiros." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Cargar unha lista de supresións de perdas do ficheiro indicado. Indique unha " +"supresión por liña, e comece cada liña con «leak:», é dicir, use o formato " +"de ficheiro de supresión de LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorar as definicións de supresións incluídas no ficheiro de datos de " +"seguimento de Heaptrack. De maneira predeterminada, Heaptrack copia as " +"supresións definidas de maneira opcional mediante o símbolo «const char " +"*__lsan_default_suppressions()» na aplicación depurada. Estas supresións " +"aplícanse sempre ao analizar os datos, a non ser que desactive a " +"funcionalidade de maneira explícita mediante esta opción da liña de ordes." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorar as supresións de definicións incluídas en Heaptrack. De maneira " +"predeterminada, Heaptrack suprime certas perdas coñecidas de bibliotecas de " +"sistema comúns." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Ficheiro a cargar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FICHEIRO…]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 asignacións de %2, %3 asignacións en total cunha media de %4 por " +"asignación." + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Tamaño da asignación solicitada" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Número de asignacións" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Abrir o ficheiro nun editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depurado:
%1 " +"(conectado)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depurado:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
tempo total de execución:
%1, filtrado de %2 a %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
tempo total de execución:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memoria total do sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
chamadas a funcións de asignación:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
asignacións temporais:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
pico de consumo de memoria dinámica:
%1 tras %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
pico de RSS (incluíndo o xerado por heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
diferenza de consumo de memoria:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
memoria total perdida:
%1 (%2 suprimido)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
memoria total perdida:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Non foi posíbel analizar o ficheiro %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumida" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Tamaños" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "O dato de entrada %1 non existen." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "O dato de entrada %1 non é un ficheiro." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "O dato de entrada %1 non pode lerse." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Non foi posíbel analizar o ficheiro de supresión." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Desactivar as supresións incluídas" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Desactivar as supresións de serie" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorar as supresións de definicións incluídas en Heaptrack. De maneira " +"predeterminada, Heaptrack suprime certas perdas coñecidas de bibliotecas de " +"sistema comúns." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Cargando o ficheiro %1…" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 en comparación con %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Analizando de novo o ficheiro…" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegación de código" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalizada…" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automático (sen números de liña)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegación personalizada de código" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Indicar a orde para usar para a navegación de código, «%f» substituirase " +"polo nome de ficheiro, «%l» polo número de liña e «%c» polo número de " +"columna." + +# well-spelled: XanelaPrincipal +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "XanelaPrincipal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "Ruta dun ficheiro con regras de supresión de perdas in formato LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Abrir os datos de Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Este campo indica o ficheiro de datos principal de Heaptrack. O nome " +"do ficheiro debe ser heaptrack.$APP.$PID.gz ou heaptrack.$APP." +"$PID.zst. Pode xerar un analizando o rendemento da súa aplicación, por " +"exemplo mediante:

\n" +"
heaptrack <aplicación> …
\n" +"

Tamén pode conectarse a un proceso en execución mediante:

\n" +"
heaptrack --pid $(pidof <aplicación>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "ruta/de/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Opcionalmente, pode indicar un segundo ficheiro de datos de Heaptrack co " +"que comparar. Se o indica, ese segundo ficheiro usarase como base e os seus " +"custos subtraeranse dos custos principais de datos." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Datos do perfil:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Comparar con:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supresións:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "ruta/das//supresións-de-lsan.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resumo" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Lista de funcións que asignaron máis memoria nun momento dado." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contribucións ao pico" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lista de funcións que perderon máis memoria." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Maiores perdas de memoria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lista de funcións que asignan memoria con maior frecuencia." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Máis asignacións de memoria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Lista de funcións que produciron a meirande parte das asignacións temporais." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Máis asignacións temporais" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supresións" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "De abaixo a arriba" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrar por función…" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrar por ficheiro…" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrar por módulo…" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Chamador / Chamado" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "De arriba a abaixo" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Gráfico de chamas" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "Rimas (s&tacks)" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Rima (stack) seleccionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Ficheiro" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Co&nfiguración" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtrar" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "xuntando as asignacións… %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "Total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "De 0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "De 9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "De 17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "De 33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "De 65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "De 129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "De 257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "De 512B a 256B" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "Máis de 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "analizando de novo os datos" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "analizando os datos" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1. Paso: %2/%3. Gastado: %4. Restante: %5." + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "xuntando as asignacións…" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "construíndo o histograma de tamaño…" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "construíndo as gráficas…" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Trazado inverso" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"O número de veces que se chamou a unha función de asignación desde aquí." +"" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"O número de asignacións temporais. Estas asignacións van seguidas " +"directamente por unha liberación sen outras asignacións entre medias." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"As contribucións en bytes desde un lugar indicado ao consumo máximo de " +"memoria dinámica (heap). Téñense en conta as liberacións." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"O lugar desde o que se chamou unha función de asignación. Poderían non " +"coñecerse o símbolo da función e a información do ficheiro se faltaba a " +"información de depuración no momento no que se executou Heaptrack." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" en %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contribución ao pico: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "perdida: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "asignacións: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporal: %1 (%2% das asignacións, %3% do total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "trazado inverso:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "chamado desde un lugar" +msgstr[1] "chamado desde %1 lugares" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% dun total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (propio): %2
  %4% dun total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusivo): %2
  %4% dun total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbolo: %1
binario: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 en %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#, fuzzy +#~| msgid "%1 allocations from %2 in %3 (%4)" +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 asignacións de %2 en %3 (%4)" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 en %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Símbolo" + +#~ msgid "Binary" +#~ msgstr "Binario" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "A función suerior que chamou a unha función de asignación. Pode que " +#~ "non se resolva se falta a información de depuración." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "O módulo (o executábel ou biblioteca compartida) desde o que se " +#~ "chamou a unha función de asignación." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "O nome de función do %1. Pode que non se resolva se falta a información " +#~ "de depuración." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "O nome do executábel no que está o símbolo." + +#~ msgid "Function" +#~ msgstr "Función" + +#~ msgid "Module" +#~ msgstr "Módulo" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "A función suerior que chamou a unha función de asignación. Pode que " +#~ "se descoñeza se falta a información de depuración." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " en %2" + +#~ msgid "File" +#~ msgstr "Ficheiro" + +#~ msgid "Line" +#~ msgstr "Liña" + +#~ msgid "Allocated (Self)" +#~ msgstr "Asignada (directa)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Asignada (total)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "O ficheiro desde o que se chamou á función. Pode que estea baleiro se " +#~ "falta a información de depuración." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "O número de liña desde o que se chamou á función. Pode que estea " +#~ "baleiro se falta a información de depuración." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "A suma de todos os bytes asignados directamente desde aquí, ignorando " +#~ "as desasignacións." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "A suma total de todos os bytes asignados desde aquí ou desde funcións " +#~ "chamadas desde aquí, ignorando as desasignacións." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " en %2:%3\n" +#~ " en %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "total: asignou %1 mediante %2 chamadas (%3 temporais, o %4), cun pico de " +#~ "%5, perdeu %6." + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "directo: asignou %1 mediante %2 chamadas (%3 temporais, o %4), cun pico " +#~ "de %5, perdeu %6." + +#~ msgid "Memory Allocated" +#~ msgstr "Memoria asignada" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 asignados en total despois de %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 asignadas despois de %3 desde:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Mostra a memoria total asignada no tempo. Este valor ignora " +#~ "liberacións e simplemente mide a asignación de memoria dinámica." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) asignado en %3 e por debaixo." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "Contribución de %1 ao pico de consumo" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 asignado en total" + +#~ msgid "Allocated" +#~ msgstr "Asignada" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Mostrar un gráfico de chamas coa memoria total asignada por funcións do " +#~ "seu código. Isto engloba todas as asignacións de memoria, sen ter en " +#~ "conta as liberacións." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 asignacións de %2 en %3:%4 en %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
bytes totais asignados (sen contar liberacións):
%1 " +#~ "(%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lista de funcións que asignaron máis memoria en xeral, sen ter en conta " +#~ "as liberacións." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Máis memoria asignada" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "A suma de todos os bytes asignados desde aquí, ignorando as " +#~ "desasignacións." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "asignada: %1 (%2% do total)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Abrir o ficheiro de saída de Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Ficheiros de datos de Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Gráficas" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "asignou %1 mediante %2 chamadas (%3 temporais, o %4), cun pico de %5, " +#~ "perdeu %6." + +#~ msgid "debuggee: %1" +#~ msgstr "depurado: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "tempo total de execución: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 en %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Asignacións [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Asignacións temporais [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Perdido [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Asignado [B]" + +#~ msgid "time in ms" +#~ msgstr "tempo en ms" + +#~ msgid "memory heap size" +#~ msgstr "tamaño do montón de memoria" diff --git a/po/ia/heaptrack.po b/po/ia/heaptrack.po new file mode 100644 index 00000000..8b643bb4 --- /dev/null +++ b/po/ia/heaptrack.po @@ -0,0 +1,1275 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# +# Giovanni Sora , 2020, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-12-13 23:18+0100\n" +"Last-Translator: giovanni \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.12.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Giovanni Sora" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "g.sora@tiscali.it" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Location" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allocationes (Self)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporanee (Self)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allocationes(Incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Allocationes" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporanee" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Allocationes de memoria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memoria consumite" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Allocationes temporanee" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tempore perimite" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Allocationes totl de memoria" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Consumo Total de Memoria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Allocationes temporanee total" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allocationes in total postea %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 allocationes temporanee in total postea %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumite in total postea%2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 allocationes postea %3 ex:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 allocationes postea %3 ex:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumite postea %3 ex:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exporta como..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Monstra legenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrar sur selection" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reinitialisa filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Salveguarda %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InitioFinDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tempore%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumate%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Allocationes%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Allocationes Temporanee%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrate ab %2 a %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Cerca..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "GUI de Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor original, mantenitor" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Files de cargar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FILE...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumate" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Dimensiones" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Reanalysante file, pro favor tu attende..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalisa..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Fenestra Principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Summario" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&File" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Prefere&ntias" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtro" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "fusionante allocationes... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "Total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "plus que 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "reanalysante datos" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "analysante datos" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "fusionante allocationes..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Retraciamento" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" in %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "allocationes: %1 (%2% de total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporanee: %1 (%2% de allocationes, %3% de total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "retraciamento:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" +msgstr[1] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% sur de %3 total" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (self): %2
  %4% sur de %3 total" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusive): %2
  %4% sur de %3 total" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbolo: %1
binari: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 In %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "Kwrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 allocationes ex %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 In %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbolo" + +#~ msgid "Binary" +#~ msgstr "Binari" + +#~ msgid "Function" +#~ msgstr "Function" + +#~ msgid "Module" +#~ msgstr "Modulo" diff --git a/po/it/heaptrack.po b/po/it/heaptrack.po new file mode 100644 index 00000000..bb6a3fe0 --- /dev/null +++ b/po/it/heaptrack.po @@ -0,0 +1,1372 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# Vincenzo Reale , 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-12 02:44+0200\n" +"Last-Translator: Vincenzo Reale \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 22.08.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vincenzo Reale" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "smart2128vr@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Posizione" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allocazioni (proprie)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporanea (propria)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Picco (propria)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Persa (propria)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allocazioni (incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporanea (incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Picco (incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Persa (incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Il simbolo genitore che chiamava una funzione di allocazione. Il nome " +"della funzione può essere irrisolto quando mancano le informazioni sul debug." +"" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Il numero di volte in cui una funzione di allocazione è stata chiamata " +"direttamente da questa posizione." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Il numero di allocazioni temporanee dirette. Queste allocazioni sono " +"seguite direttamente da una libera senza altre allocazioni in mezzo." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"La memoria massima di heap in byte consumata da allocazioni originate " +"direttamente in questa posizione. Questo tiene conto delle deallocazioni." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"I byte assegnati direttamente in questa posizione che non sono stati " +"deallocati." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Il numero inclusivo di volte in cui una funzione di allocazione è stata " +"chiamata da questa posizione o qualsiasi funzioni chiamate da qui. " + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Il numero di allocazioni temporanee inclusive. Queste allocazioni sono " +"direttamente seguite da una libera senza altre allocazioni in mezzo." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"La memoria massima di heap inclusiva in byte consumata da allocazioni " +"originate in questa posizione o dalle funzioni chiamate da qui. Questo tiene " +"conto delle deallocazioni." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"I byte assegnati in questa posizione che non sono stati deallocati." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Chiamante" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Chiamato" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Picco" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Persa" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Allocazioni" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporaneo" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"La posizione del %1. Il nome della funzione può essere irrisolto quando " +"mancano le informazioni sul debug." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"La posizione del codice sorgente che chiamava una funzione di " +"allocazione. Può essere sconosciuto quando mancano le informazioni sul debug." +"" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Allocazioni di memoria" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memoria consumata" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Allocazioni temporanee" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tempo trascorso" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Allocazioni di memoria totali" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Consumo totale di memoria" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Allocazioni temporanee totali" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 byte)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allocazioni in totale dopo %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 allocazioni temporanee in totale dopo %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumati in totale dopo %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 allocazioni dopo %3 da:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 allocazioni temporanee dopo %3 da:

%1" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumati dopo %3 da:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Esporta come..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostra legenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostra il grafico del costo totale" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostra il grafico dettagliato dei costi" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagrammi a colonne:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtro sulla selezione" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Azzera filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Salva %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Immagine raster (*.png *.jpg *.tiff);;Immagine vettoriale (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Impossibile salvare l'immagine in %1." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InizioFineDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tempo%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumati%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Allocazioni%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Allocazioni temporanee%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Mostra il consumo di memoria heap nel tempo.
Fai clic e trascina per " +"selezionare un intervallo di tempo per il filtro.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra il numero di allocazioni di memoria nel tempo.
Fai clic e " +"trascina per selezionare un intervallo di tempo per il filtro.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra il numero di allocazioni temporanee di memoria nel tempo. " +"Un'allocazione temporanea è quella che viene seguita immediatamente dalla " +"deallocazione corrispondente, senza altre allocazioni che si verificano in " +"mezzo.
Fai clic e trascina per selezionare un intervallo di tempo per il " +"filtro.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrato da %2 a %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta filtrato)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Fai clic e trascina per selezionare l'intervallo di tempo per il filtro." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, consumato: %2. Fai clic e trascina per selezionare l'intervallo di " +"tempo per il filtro." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, allocazioni: %2. Fai clic e trascina per selezionare l'intervallo di " +"tempo per il filtro." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, allocazioni temporanee: %2. Fai clic e trascina per selezionare " +"l'intervallo di tempo per il filtro." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 allocazioni in totale" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 allocazioni temporanee in totale" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 consumo di memoria di picco" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 persi in totale" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) allocazioni in %3 e inferiori." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) allocazioni temporanee in %3 e inferiori." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contributi al consumo di picco in %3 e inferiori." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) persi in%3 e inferiore." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Picco di memoria" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostra un grafico a fiamma sui contributi al consumo di memoria di picco " +"della tua applicazione." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostra un grafico a fiamma sopra la memoria heap persa dell'applicazione. La " +"memoria è considerata persa quando non è mai deallocata." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostra un grafico a fiamma sul numero di allocazioni attivate dalle funzioni " +"nel tuo codice." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostra un grafico a fiamma sul numero di allocazioni temporanee innescate " +"dalle funzioni nel tuo codice. Le allocazioni sono contrassegnate come " +"temporanee quando vengono immediatamente seguite dalla loro deallocazione." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Seleziona l'origine dati che deve essere visualizzata nel grafico a fiamma." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista dal basso verso l'alto" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Abilita la vista grafico a fiamma dal basso verso l'alto. Se non viene " +"marcata, la vista dall'alto verso il basso è abilitata per impostazione " +"predefinita." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Contrai la ricorsione" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Contrai dei frame dello stack per le funzioni che invocano se stesse. Se non " +"è marcato, i frame ricorsivi saranno visualizzati separatamente." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Soglia di costo: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"La soglia di costo definisce un valore di taglio frazionario. Gli " +"elementi con un costo relativo al di sotto di questo valore non saranno " +"visualizzati nel grafico a fiamma. Questo viene fatto come ottimizzazione " +"per generare rapidamente grafici per insiemi di dati di grandi dimensioni " +"con sovraccarico di memoria bassa. Se hai bisogno di maggiori dettagli, " +"riduci il valore di soglia o impostarlo su zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Cerca..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Cerca il grafico a fiamma per un simbolo." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Ripristina la vista" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Visualizza il chiamante/chiamato" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "generazione del grafico a fiamma..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% del totale di %3) allocazioni verificate dalla ricerca." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% del totale di %3) verificate per ricerca." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interfaccia di Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Un visualizzatore per i file di dati di heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autore originale, responsabile" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Base dei dati del profilo con la quale confrontare gli altri file." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Elenco di caricamento delle soppressioni di perdite dal file specificato. " +"Specifica una soppressione per riga e inizia ogni riga con «leak», ovvero " +"utilizza il formato del file di soppressione LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignora le definizioni di soppressione che sono incorporate nel file di dati " +"heaptrack. Per impostazione predefinita, heaptrack copierà le soppressioni " +"facoltativamente definite tramite un simbolo `const char *__ " +"lsan_default_suppressions ()` nell'applicazione Debuggee. Queste sono sempre " +"applicati durante l'analisi dei dati, a meno che questa funzionalità non sia " +"esplicitamente disabilitata utilizzando questa opzione della riga di comando." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignora le definizioni di soppressione integrate in heaptrack. Per " +"impostazione predefinita, heaptrack sopprimerà alcune perdite note nelle " +"librerie di sistema comuni." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "File da caricare" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FILE...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 allocazioni da %2, totale %3 allocato con una media di %4 per allocazione" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Dimensione di allocazione richiesta" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Numero di allocazioni" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Apri il file nell'editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
debuggee:
%1 " +"(allegato)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
debuggee:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
tempo di esecuzione totale:
%1, filtrato da %2 a %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
tempo di esecuzione totale:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memoria di sistema totale:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" +"
chiamate alle funzioni di allocazione:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
allocazioni temporanee:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
consumo di memoria heap di picco:
%1 dopo %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
RSS picco (incluso il sovraccarico di heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta del consumo di memoria:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
memoria totale persa:
%1 (%2 soppressi)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
memoria totale persa:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Impossibile analizzare il file %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumata" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Dimensioni" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "I dati di ingresso %1 non esistono." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "I dati di ingresso %1 non sono un file." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "I dati di ingresso %1 non sono leggibili." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Impossibile analizzare il file di soppressione." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Disabilitare le soppressioni integrate" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Disabilita le soppressioni incorporate" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignora le definizioni di soppressione integrate in heaptrack. Per " +"impostazione predefinita, heaptrack sopprimerà alcune perdite note dalle " +"libreria di sistema comuni." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Caricamento del file %1, attendi..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 confrontato con %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Nuova elaborazione del file, attendi..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navigazione nel codice" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalizzato..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatico (nessun numero di riga)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navigazione nel codice personalizzata" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Specifica il comando da utilizzare per la navigazione del codice, «%f» sarà " +"sostituito dal nome del file, «%l» dal numero di riga e «%c» dal numero di " +"colonna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Finestra principale" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Percorso a un file contenente regole di soppressione delle perdite nel " +"formato LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Apri dati di Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Questo campo specifica il file di dati heaptrack principale. Questi " +"file sono chiamati heaptrack. $APP.$PID.gz o heaptrack.$APP." +"$PID.zst. Puoi produrre un file del genere profilando la tua " +"applicazione, ad es. tramite:

\n" +"
heaptrack <latuaapplicazione> ...
\n" +"

o, in alternativa, puoi collegarti a un processo di esecuzione tramite\n" +"

heaptrack --pid $(pidof <latuaapplicazione>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "percorso/a/heaptrack.$APP.$PID.{gz, zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Puoi specificare facoltativamente un secondo file di dati heaptrack da " +"confrontare. Se impostato, questo file sarà utilizzato come base e il suo " +"costo viene sottratto dai costi di dati principali." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dati profilo:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Confronta con:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Soppressioni:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "percorso/a/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Riepilogo" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Elenco di funzioni che hanno allocato la maggior parte della memoria in un " +"determinato momento." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contributi di picco" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Elenco di funzioni che perdono la maggior parte della memoria." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Perdite di memoria più grandi" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Elenco di funzioni che allocano la memoria più spesso." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Maggior parte delle allocazioni di memoria" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Elenco di funzioni che hanno prodotto la maggior parte delle allocazioni di " +"memoria temporanee." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Maggior parte delle allocazioni temporanee" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Soppressioni" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Dal basso verso l'alto" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtra per funzione..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtra per file..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtra per modulo..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Chiamante / Chiamato" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Dall'alto al basso" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Grafico a fiamma" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tack" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Stack selezionato:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&File" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Impostazio&ni" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtro" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "unione delle allocazioni... %1 %" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "totale" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "da 0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "da 9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "da 17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "da 33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "da 65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "da 129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "da 257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "da 512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "più di 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "nuova elaborazione dei dati" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "elaborazione dati" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 passaggio: %2/%3 speso: %4 rimanente: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "unione delle allocazioni..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "generazione dell'istogramma delle dimensioni..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "generazione dei grafici..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Il numero di volte in cui una funzione di allocazione è stata invocata " +"da questa posizione." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Il numero di allocazioni temporanee. Queste allocazioni sono " +"direttamente seguite da una libera senza altre allocazioni in mezzo." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"I contributi da una determinata posizione al consumo di memoria massimo " +"in byte. Questo tiene conto delle deallocazioni." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"La posizione da cui era stata invocata una funzione di allocazione. Il " +"simbolo della funzione e le informazioni sul file possono essere sconosciute " +"quando mancavano informazioni sul debug durante l'esecuzione di heaptrack. " + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" in %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contributo di picco: %1 (%2% del totale)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "persa: %1 (%2% del totale)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "allocazioni: %1 (%2% del totale)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporanea: %1 (%2% delle allocazioni, %3% del totale)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "chiamato da una posizione" +msgstr[1] "chiamato da %1 posizioni" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% di %3 totali" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (self): %2
   %4 % su %3 totali" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusi): %2
   %4% su %3 totali" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "simbolo: %1
binario: %2 (%3) " + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 in %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" diff --git a/po/ja/heaptrack.po b/po/ja/heaptrack.po new file mode 100644 index 00000000..0ef91e54 --- /dev/null +++ b/po/ja/heaptrack.po @@ -0,0 +1,1226 @@ +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2015-06-28 12:25-0700\n" +"Last-Translator: Japanese KDE translation team \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr "" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/ka/heaptrack.po b/po/ka/heaptrack.po new file mode 100644 index 00000000..dad76730 --- /dev/null +++ b/po/ka/heaptrack.po @@ -0,0 +1,1257 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-01-17 06:04+0100\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.2.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "რუსუდან ცისკრელი" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "Temuri.doghonadze@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "მდებარეობა" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "გამოყოფები (თვით)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "დროებითი (თვით)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "პიკი (თვით)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "გაჟონილი (თვით)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "გამოყოფები (ჩათვლ.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "დროებითი (ჩათვლ.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "პიკი (ჩათვლ.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "გაჟონილი (ჩათვლ.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "მდებარეობაზე ბაიტები გამოიყო, მაგრამ არ გათავისუფლებულა.." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "გამომძახებელი" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "გამოძახებული" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "პიკი" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "გაჟონილი" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "გამოყოფები" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "დროებითი" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "მეხსიერების გამოყოფები" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "დახარჯული მეხსიერება" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "დროებით გამოყოფები" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "გასული დრო" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "მეხსიერების გამოყოფები ჯამში" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "დახარჯული მეხსიერება ჯამში" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "დროებით გამოყოფები ჯამში" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 ბაიტი)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allocations in total after %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "გატანა, როგორც..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "ახსნის ჩვენება" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "ჯამური ღირებულების გრაფიკის ჩვენება" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "დეტალური ღირებულების გრაფიკის ჩვენება" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "მიწყობილი დიაგრამები:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "ჩართული მონიშნულის გაფილტვრა" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "ფილტრის გასუფთავება" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "%1-ის შენახვა" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" +"რასტრული გამოსახულება (*.png *.jpg *.tiff);;ვექტორული გამოსახულება (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "გამოსახულების %1-ში შენახვის შეცდომა" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "დასაწყისიდასასრულიდელტა" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "დრო%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "დახარჯული%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "გამოყოფები%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "დროებითი გამოყოფები%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (გაფილტრულია %2-დან %3-მდე, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (გაფილტრული დელტა)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 გამოყოფები სულ" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 დროებითი გამოყოფები სულ" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 პიკური მეხსიერების მოხმარება" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 გაჟონილი სულ" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "პიკური მეხსიერება" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "რეკურსიის ჩაკეცვა" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "ღირებულების ზღვარი: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "ძებნა..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "ხედის საწყის მნიშვნელობაზე დაბრუნება" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "გამოძახებული/გამომძახებლის ნახვა" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack-ის ინტერფეისი" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "ავტორი და პროექტის პირველი ხელმძღვანელი" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "ჩასატვირთი ფაილები" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[ფაილი...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "გამოყოფის მოთხოვნილი ზომა" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "გამოყოფების რაოდენობა" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "ფაილის რედაქტორში გახსნა" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
გამმართველი:
%1 " +"(მიმაგრებულია)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
გასამართი:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "%1 ფაილის დამუშავების შეცდომა." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "მოხმარებულია" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "ზომები" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "შეყვანილი მონაცემი %1 არ არსებობს." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "შეყვანილი მონაცემი %1 ფაილი არაა." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "შეყვანილი მონაცემი %1 წაკითხვადი არაა." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "ჩახშობის ფაილის დამუშავების შეცდომა." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "ჩაშენებული ჩახშობების გამორთვა" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "ჩადგმული ჩახშობების გამორთვა" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "იტვირთება ფაილი %1. მოითმინეთ..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "ფაილის თავიდან დამუშავება. გთხოვთ მოიცადოთ..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "დოკუმენტის ნავიგაცია" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "ხელით..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "ავტომატური (ხაზის ნომრების გარეშე)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "ხელით მითითებულ კოდში ნავიგაცია" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "მთავარი ფანჯარა" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "ბილილი/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "პროფილის &მონაცემები:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "შედარება:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "ჩახშობები:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "ბილიკი/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "შეჯამება" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "უმაღლესი წვლილი" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "ფუნქციების სია, რომლებიც ყველაზე მეტ მეხსიერებას ჟონავენ." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "მეხსიერების ყველაზე დიდი გაჟონვები" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "ფუნქციების სია, რომლებიც მეხსიერებას ყველაზე ხშირად გამოყოფენ." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "მეხსიერების გამყოფების უმრავლესობა" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "დროებით გამოყოფების უმრავლესობა" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&ფაილი" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "&მორგება" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "ფილტრი" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "გამოყოფების შერწყმა... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "ჯამში" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0ბ-დან 8ბმ-მდე" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9ბ-დან 16ბ-მდე" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17ბ-დან 32ბ-მდე" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33ბ-დან 64ბ-მდე" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "64ბ-დან 128ბ-მდე" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129ბ-დან 256ბ-მდე" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257ბ-დან 512ბ-მდე" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512ბ-დან 1კბ-მდე" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "1კბ-ზე მეტი" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "მონაცემების თავიდან დამუშავება" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "მონაცემების დამუშავება" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 გაიარა: %2/%3 დახარჯა: %4 დარჩა: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "გამოყოფების შერწყმა..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "ზომის ჰისტოგრამის აგება..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "გრაფიკების აგება...." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "შეცდომის მიდევნება" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" %2-ში (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "პიკური წვლილი: %1 (სულ %2%)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "გაჟონვა: %1 (სულ %2%)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "გამოყოფები: %1 (სულ %2%)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "დროებითი: %1 (გამოყოფების %2%, სულ %3%)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "გამოძახებულია 1 მდებარეობიდან" +msgstr[1] "გამოძახებულია %1 მდებარეობიდან" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% ჯამში %3-დან" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (თვით): %2
  %4% ჯამში %3-დან" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (ჩათვლით): %2
  %4% ჯამში %3-დან" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "სიმბოლო: %1
ბინარული: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1-ი %2-ში" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "<ამოუხსნელი ფუნქცია>" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" diff --git a/po/ko/heaptrack.po b/po/ko/heaptrack.po new file mode 100644 index 00000000..dc4529f5 --- /dev/null +++ b/po/ko/heaptrack.po @@ -0,0 +1,1381 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# Shinjo Park , 2020, 2021, 2022, 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-04-21 23:40+0200\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "박신조" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde@peremen.name" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "위치" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "할당(자체)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "임시(자체)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "극값(자체)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "누수됨(자체)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "할당(포함)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "임시(포함)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "극값(포함)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "누수됨(포함)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"할당 함수를 호출한 부모 기호입니다. 디버그 정보가 없다면 함수 이름을 파악" +"하지 못할 수도 있습니다." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "이 위치에서 할당 함수가 직접 호출된 횟수입니다." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"직접 임시 할당 횟수입니다. 이렇게 할당된 메모리는 중간에 다른 할당 없이 " +"free로 바로 해제됩니다." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"이 위치에서 직접 호출된 할당에서 사용한 최대 힙 메모리 크기(바이트 단위)" +"입니다. 할당 해제를 계산합니다." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"이 위치에서 직접 할당된 메모리 중 할당 해제되지 않은 바이트 수입니다." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"이 위치 또는 여기에서 호출된 함수를 포함하여 할당 함수가 호출된 횟수입니" +"다." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"포함된 임시 할당 횟수입니다. 이렇게 할당된 메모리는 중간에 다른 할당 없" +"이 free로 바로 해제됩니다." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"이 위치 또는 여기에서 호출된 함수를 포함하여 할당에서 사용한 최대 힙 메모" +"리 크기(바이트 단위)입니다. 할당 해제를 계산합니다." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"이 위치에서 할당된 메모리 중 할당 해제되지 않은 바이트 수입니다." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "호출자" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "피호출자" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "극" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "누수됨" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "할당" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "임시" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"%1의 위치입니다. 디버그 정보가 없다면 함수 이름을 파악하지 못할 수도 있습니" +"다." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"할당 함수를 호출한 소스 코드 위치입니다. 디버그 정보가 없다면 파악하지 못" +"할 수도 있습니다." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "메모리 할당" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "사용한 메모리" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "임시 할당" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "경과 시간" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "총 메모리 할당" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "총 메모리 사용량" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "최대 임시 할당" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1(%2바이트)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%2 이후 총 할당 %1회" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%2 이후 총 임시 할당 %1회" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%2 이후 총 %1 사용됨" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%3 이후 할당 %2회, 위치:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%3 이후 임시 할당 %2회, 위치:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%3 이후 %2 사용됨, 위치:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "다른 이름으로 내보내기..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "범례 표시" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "전체 비용 그래프 표시" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "자세한 비용 그래프 표시" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "겹쳐진 다이어그램:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "선택할 때에 필터" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "필터 초기화" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "%1 저장" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "래스터 그림 (*.png *.jpg *.tiff);;벡터 그림 (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "그림을 %1(으)로 저장할 수 없음" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "시작끝차이" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "시간%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "사용함%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "할당%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "임시 할당%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"시간별 힙 메모리 사용량을 표시합니다.
필터링할 시간 범위를 선택하려면 " +"클릭하고 드래그하십시오.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"시간별 메모리 할당 횟수를 표시합니다.
필터링할 시간 범위를 선택하려면 " +"클릭하고 드래그하십시오.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"시간별 임시 메모리 할당 횟수를 표시합니다. 임시 메모리 할당은 메모리를 할" +"당한 후 할당 해제하기 전까지 다른 할당이 일어나지 않은 메모리 할당입니다.
" +"필터링할 시간 범위를 선택하려면 클릭하고 드래그하십시오.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1(%2부터 %3까지 필터링됨, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1(필터된 차이)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "필터링할 시간 범위를 선택하려면 클릭하고 드래그하십시오." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, 사용함: %2. 필터링할 시간 범위를 선택하려면 클릭하고 드래그하십시오." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, 할당: %2. 필터링할 시간 범위를 선택하려면 클릭하고 드래그하십시오." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, 임시 할당: %2. 필터링할 시간 범위를 선택하려면 클릭하고 드래그하십시" +"오." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "총 할당 %1회" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "총 임시 할당 %1회" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "메모리 사용량 극값 %1" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "총 누수 %1" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%3 및 아래에서 할당이 %1회(%2%) 일어났습니다." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%3 및 아래에서 임시 할당이 %1회(%2%) 일어났습니다." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%3 및 아래에서 메모리 소모 극값의 %1(%2%)를 차지합니다." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%3 및 아래에서 %1(%2%)의 메모리가 누수되었습니다." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "메모리 극값" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"앱의 힙 메모리 사용량 극값에서 차지하는 비중을 나타내는 불꽃 그래프를 표시합" +"니다." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"앱의 힙 메모리 누수량에서 차지하는 비중을 나타내는 불꽃 그래프를 표시합니다. " +"할당 해제되지 않은 메모리는 누수된 것으로 간주합니다." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"코드의 함수에서 할당을 트리거한 횟수를 나타내는 불꽃 그래프를 표시합니다." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"코드의 함수에서 임시 할당을 트리거한 횟수를 나타내는 불꽃 그래프를 표시합니" +"다. 메모리가 할당된 후 곧바로 해제되면 임시 할당으로 간주합니다." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "불꽃 그래프에 표시할 데이터 원본을 선택합니다." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "아래에서 위로 보기" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"불꽃 보기에서 맨 마지막으로 호출된 함수를 위쪽에 표시합니다. 이 옵션을 선택하" +"지 않으면 기본값으로 맨 처음으로 호출된 함수를 아래쪽에 표시합니다." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "재귀 함수 접기" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"재귀 호출을 하는 함수를 스택 프레임에서 접습니다. 이 옵션을 선택하지 않으면 " +"재귀 호출의 각각 프레임을 별개로 표시합니다." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "비용 하한선: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"비용 하한선은 표시할 값의 하한선을 지정합니다. 상대 비용이 해당 값보다 낮" +"은 항목은 불꽃 그래프에 표시하지 않습니다. 데이터가 클 때 메모리를 적게 사용" +"하여 그래프를 생성하려고 사용합니다. 더 많은 정보를 표시하려면 값을 내리거나 " +"0으로 지정하십시오." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "찾기..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "불꽃 그래프에서 기호를 검색합니다." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "보기 초기화" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "호출자/피호출자 보기" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "불꽃 그래프 생성 중..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "검색과 일치하는 할당이 총 %1회(전체 %3회 중 %2%) 있습니다." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "검색과 일치하는 항목이 총 %1(전체 %3 중 %2%) 있습니다." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "힙 추적 GUI" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "힙 추적 데이터 파일을 시각화합니다." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "원 작성자, 관리자" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "다른 파일을 비교할 기본 프로필 데이터입니다." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"지정한 파일에서 누수 억제 목록을 불러옵니다. 한 줄에 하나씩 지정하십시오. 각 " +"줄은 'leak:'으로 시작하는 LSAN 억제 파일 형식이어야 합니다." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"힙 추적 데이터 파일에 임베드된 억제 정의를 무시합니다. 기본적으로 힙 추적에서" +"는 디버그되는 앱의 `const char *__lsan_default_suppressions()` 기호를 통해 추" +"가로 정의된 억제 정의를 복사합니다. 이 명령행 옵션으로 명시적으로 비활성화하" +"지 않는 한 데이터를 분석할 때 항상 적용됩니다." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"힙 추적에 내장된 억제 정의를 무시합니다. 기본값으로 힙 추적에서는 시스템 라이" +"브러리에 있는 알려진 메모리 누수를 무시합니다." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "불러올 파일" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[파일...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "%2에서 할당 %1회, 총 할당량 %3, 할당당 평균 %4" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "요청한 할당 크기" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "할당 횟수" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "편집기에서 파일 열기" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
디버그할 파일:
%1(디버" +"거 연결됨)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
디버그할 파일:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
총 실행 시간:
%1, %2부터 %3깨지 필터링됨(%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
총 실행 시간:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
총 시스템 메모리:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
할당 함수 호출:
%1(%2/초)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
임시 할당:
%1(%2%, %3/초)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
힙 메모리 할당 극값:
%2 후 %1
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
RSS 극값(힙 추적 오버헤드 포함):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
메모리 사용량 차이:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
총 메모리 누수:
%1(%2 억제됨)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
총 메모리 누수:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "%1 파일을 해석할 수 없습니다." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "사용함" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "크기" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "입력 데이터 %1이(가) 없습니다." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "입력 데이터 %1이(가) 파일이 아닙니다." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "입력 데이터 %1에서 읽을 수 없습니다." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "억제 파일을 해석할 수 없습니다." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "힙 추적" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "임베드된 억제 비활성화" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "내장된 억제 비활성화" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"힙 추적에 내장된 억제 정의를 무시합니다. 기본값으로 힙 추적에서는 시스템 라이" +"브러리에 있는 알려진 메모리 누수를 무시합니다." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "파일 %1 불러오는 중, 잠시 기다려 주십시오..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "힙 추적 - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "힙 추적 - %1, %2 비교" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "파일 다시 분석하는 중, 잠시 기다려 주십시오..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "코드 탐색" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "사용자 정의..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "자동(줄 번호 없음)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "사용자 정의 코드 탐색" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"코드를 탐색할 명령어를 입력하십시오. '%f'는 파일 이름, '%l'은 줄 번호, " +"'%c'는 칸 번호로 대체됩니다." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "주 창" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "LSAN 형식으로 되어 있는 누수 억제 규칙 파일의 경로입니다." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "힙 추적 데이터 열기" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

이 필드는 주 힙 추적 데이터 파일을 지정합니다. 이 파일은 " +"heaptrack.$APP.$PID.gz 또는 heaptrack.$APP.$PID.zst 형식을 " +"갖고 있습니다. 다음 명령을 통해서 앱 프로필 데이터를 생성할 수 있습니다:\n" +"

heaptrack <yourapplication> ...
\n" +"

실행 중인 앱에 연결할 수도 있습니다:

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "path/to/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"선택 사항으로 비교할 두 번째 힙 추적 데이터를 지정할 수 있습니다. 두 번" +"째 파일을 지정하면 해당 파일을 기반 파일로 사용하고 비용을 첫 번째 파일의 비" +"용에서 뺍니다." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "프로필 데이터(&D):" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "다음과 비교:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "억제:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "path/to/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "요약" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "지정한 시간에 최대로 메모리를 많이 할당한 함수 목록입니다." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "극값 비중" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "최대로 메모리 누수가 큰 함수 목록입니다." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "최대 메모리 누수" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "가장 자주 메모리를 할당한 함수 목록입니다." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "최대 메모리 할당" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "최대로 임시 할당 횟수가 많은 함수 목록입니다." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "최대 임시 할당" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "억제" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "아래에서 위로" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "함수로 필터하기..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "파일로 필터하기..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "모듈로 필터하기..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "호출자/피호출자" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "위에서 아래로" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "불꽃 그래프" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "스택(&T)" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "선택한 스택:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "파일(&F)" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "설정(&N)" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "필터" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "할당 합치는 중... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "합계" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0 B-8 B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9 B-16 B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17 B-32 B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33 B-64 B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65 B-128 B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129 B-256 B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257 B-512 B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 B-1 KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "1 KB 초과" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "데이터 다시 분석 중" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "데이터 처리 중" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 합격: %2/%3 소모: %4 남음: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "할당 합치는 중..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "크기 히스토그램 생성 중..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "차트 생성 중..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "역추적" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "이 위치에서 할당 함수가 호출된 횟수입니다." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"임시 할당 횟수입니다. 이렇게 할당된 메모리는 중간에 다른 할당 없이 free" +"로 바로 해제됩니다." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"지정한 위치에서 최대 힙 메모리 크기 사용량(바이트 단위)에서 차지하는 부분" +"입니다. 할당 해제를 계산합니다." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"할당 함수가 호출된 위치입니다. 힙 추적 도구가 실행 중일 때 디버그 정보가 " +"없었다면 함수 기호와 파일 정보를 사용하지 못할 수도 있습니다." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" %2(%3)의" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "극값에서의 비중: %1(합계 중 %2%)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "누수: %1(합계 중 %2%)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "할당: %1(합계 중 %2%)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "임시: %1(할당 중 %2%, 합계 중 %3%)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "역추적:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "위치 %1곳에서 호출됨" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  총 %3 중 %4%" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1(자신): %2
  총 %3 중 %4%" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1(포함): %2
  총 %3 중 %4%" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "기호: %1
이진 파일: %2(%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%2의 %1" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "<해결되지 않은 함수>" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%2에서 할당 %1회" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1(%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%2(%3)의 %1" + +#~ msgid "Symbol" +#~ msgstr "기호" + +#~ msgid "Binary" +#~ msgstr "2진수" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "할당 함수를 호출한 부모 함수입니다. 디버그 정보가 없다면 함수 이름을 " +#~ "파악하지 못할 수도 있습니다." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "할당 함수를 호출한 모듈(실행 파일이나 공유 라이브러리)입니다." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "%1의 함수 이름입니다. 디버그 정보가 없다면 함수 이름을 파악하지 못할 수도 " +#~ "있습니다." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "기호가 있는 실행 파일의 이름입니다." + +#~ msgid "Function" +#~ msgstr "함수" + +#~ msgid "Module" +#~ msgstr "모듈" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "할당 함수를 호출한 부모 함수입니다. 디버그 정보가 없다면 함수 이름을 " +#~ "파악하지 못할 수도 있습니다." diff --git a/po/lt/heaptrack.po b/po/lt/heaptrack.po new file mode 100644 index 00000000..64922a2e --- /dev/null +++ b/po/lt/heaptrack.po @@ -0,0 +1,1233 @@ +# Lithuanian translations for trunk-kf package. +# Copyright (C) 2015 This_file_is_part_of_KDE +# This file is distributed under the same license as the trunk-kf package. +# Automatically generated, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: trunk-kf 5\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2015-08-11 11:40+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: lt\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n" +"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr "" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/nl/heaptrack.po b/po/nl/heaptrack.po new file mode 100644 index 00000000..2da2d607 --- /dev/null +++ b/po/nl/heaptrack.po @@ -0,0 +1,1602 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Freek de Kruijf , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-05 15:21+0200\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.08.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Freek de Kruijf - t/m 2021" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "freekdekruijf@kde.nl" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Locatie" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Allocaties (zelf)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Tijdelijk (zelf)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Piek (zelf)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Gelekt (zelf)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Allocaties (incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Tijdelijk (incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Piek (incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Gelekt (incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Het hogere symbool die een allocatiefunctie heeft aangeroepen. De " +"functienaam kan onbekend zijn wanneer debug-informatie ontbreekt." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Het aantal keren dat een allocatiefunctie direct is aangeroepen vanuit " +"deze locatie." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Het aantal directe tijdelijke allocaties. Deze allocaties worden direct " +"gevolgd door een vrijgave zonder enige andere allocatie er tussendoor." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Het maximale heap-geheugen in bytes gebruikt vanuit allocaties direct " +"komende van deze locatie. Dit neemt deallocaties in rekening." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"De direct gealloceerde bytes op deze locatie die niet gedealloceerd zijn." +"" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Het inclusieve aantal keren dat een allocatiefunctie is aangeroepen " +"vanuit deze locatie." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Het aantal inclusieve tijdelijke allocaties. Deze allocaties worden " +"direct gevolgd door een vrijgave zonder enige andere allocatie er tussendoor." +"" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Het inclusieve maximale heap-geheugen in bytes gebruikt vanuit " +"allocaties komende van deze locatie of van functies vanaf hier aangeroepen. " +"Dit neemt deallocaties in rekening." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"De gealloceerde bytes op deze locatie die niet gedealloceerd zijn." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Aanroeper" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Aangeroepene" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Piek" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Gelekt" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Toewijzingen" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Tijdelijk" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"De locatie van de %1. De functienaam kan niet-opgelost zijn wanneer debug-" +"informatie ontbreekt." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"De locatie in de broncode die een allocatiefunctie heeft aangeroepen. " +"Kan onbekend zijn wanneer debug-informatie ontbreekt." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Geheugenallocaties" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Gebruikt geheugen" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Tijdelijke allocaties" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Verstreken tijd" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Totale geheugenallocaties" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Totaal geheugengebruik" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Totale tijdelijke allocaties" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 allocaties in totaal na %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 tijdelijke allocaties in totaal na %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 gebruikt in totaal na %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 allocaties na %3 van:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 tijdelijke allocaties na %3 van:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 gebruikt na %3 van:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exporteren als..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Legenda tonen" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Grafiek met totale kosten tonen" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Grafiek met gedetailleerde kosten tonen" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Gestapelde diagrammen:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Erin filteren op selectie" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Filter resetten" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "%1 opslaan" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Rasterafbeelding (*.png *.jpg *.tiff);;Vectorafbeelding (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Opslaan van de afbeelding naar %1 is mislukt" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "BeginEindeDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tijd%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Gebruikt%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Toewijzingen%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Tijdelijke allocaties%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Toont het heap-geheugengebruik in de tijd.
Klik en versleep om een " +"tijdreeks voor filtering te selecteren.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Toont het aantal allocaties van geheugen in de tijd.
Klik en sleep om " +"een tijdreeks voor filtering te selecteren.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Toont het aantal tijdelijke allocaties in de tijd. Een tijdelijke " +"allocatie is er een die onmiddelijk gevolgd wordt door een overeenkomstige " +"deallocatie, zonder enige andere allocatie er tussendoor.
Klik en sleep " +"om een tijdreeks voor filtering te selecteren.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (gefilterd uit %2 tot %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (gefilterde delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Klik en sleep om een tijdreeks voor filtering te selecteren." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, geconsumeerd: %2. Klik en sleep om een tijdreeks voor filtering te " +"selecteren." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Toekenningen: %2. Klik en sleep om een tijdreeks voor filtering te " +"selecteren." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Tijdelijke toekenningen: %2. Klik en sleep om een tijdreeks voor " +"filtering te selecteren." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 allocaties in totaal" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 tijdelijke allocaties in totaal" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 geheugengebruik in de piek" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 gelekt in totaal" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) allocaties in %3 en eronder." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) tijdelijke allocaties in %3 en eronder." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) bijdrage piekgebruik in %3 en eronder." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) gelekt in %3 en eronder." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Geheugenpiek" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Een waarschuwingsgrafiek over de bijdrage in piekconsumptie van heap-" +"geheugen van uw toepassing." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Een waarschuwingsgrafiek over het gelekte heap-geheugen van uw toepassing. " +"Geheugen wordt als gelekt beschouwd als het nooit wordt gedealloceerd. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Een waarschuwingsgrafiek met het aantal allocaties gestart door functies in " +"uw code." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Een waarschuwingsgrafiek met het aantal tijdelijke allocaties gestart door " +"functies in uw code. Allocaties worden gemarkeerd als tijdelijk wanneer ze " +"onmiddellijk gevolgd worden door hun deallocatie." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"De gegevensbron selecteren die gevisualiseerd moet worden in de " +"waarschuwingsgrafiek." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Weergave van beneden naar boven" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"De weergave van de bottom-up waarschuwingsgrafiek inschakelen. Wanneer dit " +"niet is geactiveerd, zal de top-down weergave standaard zijn ingeschakeld." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Recursie invouwen" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Stackframes invouwen voor functies die zichzelf aanroepen. Wanneer dit niet " +"is gedeactiveerd zullen recursieve frames afzonderlijk gevisualiseerd worden." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Grenswaarde van kosten: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"De grenswaarde van kosten definieert een fractionele afsnijwaarde. Items " +"met relatieve kosten onder deze waarde zullen niet getoond worden in de " +"waarschuwingsgrafiek. Dit is gedaan als een optimalisatie om snel grafieken " +"te genereren voor grote gegevenssets met lage overhead van geheugen. Als u " +"meer details nodig hebt, verlaag dan de grenswaarde of stel deze op nul." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Zoeken..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "De waarschuwingsgrafiek doorzoek op een symbool een symbool." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Beeld herstellen" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Aanroeper/aangeroepene tonen" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "flame-grafiek genereren..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" +"%1 (%2% van een totaal van %3) toekenningen kwamen overeen bij de " +"zoekopdracht." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% van een totaal van %3) kwamen overeen bij de zoekopdracht." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack-GUI" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" +"Een programma voor het zichtbaar maken van gegevensbestanden van heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Oorspronkelijke auteur, onderhouder" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Basisprofielgegevens om andere bestanden mee te vergelijken." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Lijst met lekonderdrukkingen ui het gespecificeerde bestand laden. " +"Specificeer één onderdrukking per regel en start elke regel met 'leak:', d.w." +"z. gebruik het LSAN onderdrukkingsbestandsformaat." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Onderdrukkingsdefinities negeren die ingebed zijn in het " +"heaptrackgegevensbestand. Heaptrack zal standaard de onderdrukkingen " +"optioneel gedefinieerd via een `const char *__lsan_default_suppressions()` " +"symbool in de debuggee-toepassing kopiëren. Deze worden dan altijd " +"toegepast bij analyseren van de gegevens, tenzij deze functie expliciet is " +"uitgeschakeld met deze optie op de opdrachtregel." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Definities voor onderdrukken die in heaptrack zijn gebouwd negeren. " +"Standaard zal heaptrack bepaalde bekende lekken in gezamenlijke " +"systeembibliotheken onderdrukken." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Te laden bestanden" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[BESTAND...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 allocaties van %2, met in totaal %3 gealloceerd met een gemiddelde van %4 " +"per allocatie" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Gevraagde grootte van allocatie" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Aantal allocaties" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Bestand in de bewerker openen" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
debuggee:
%1 " +"(aangekoppeld)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
debuggee:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
totale uitvoeringstijd:
%1, gefilterd uit %2 tot %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
totale uitvoeringstijd:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
totaal systeemgeheugen:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
aanroepen naar allocatiefuncties:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
tijdelijke allocaties:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
piekgebruik heap-geheugen:
%1 na %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
piek-RSS (inclusief heaptrack overhead):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
geheugengebruikdelta:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
totaal gelekt geheugen:
%1 (%2 onderdrukt)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
totaal gelekt geheugen:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Ontleden is mislukt van bestand %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Gebruikt" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Groottes" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Invoergegevens %1 bestaat niet." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Invoergegevens %1 is geen bestand." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Invoergegevens %1 is niet te lezen." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Ontleden van onderdrukkingsbestand is mislukt." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Ingebedde onderdrukkingen uitschakelen" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Ingebouwde onderdrukkingen uitschakelen" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Definities voor onderdrukken die in heaptrack zijn gebouwd negeren. " +"Standaard zal heaptrack bepaalde bekende lekken uit gezamenlijke " +"systeembibliotheken onderdrukken." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Bestand %1 wordt geladen, even geduld..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 vergeleken met %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Bestand wordt opnieuw ontleed, even geduld..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Code-navigatie" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Aangepast..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatisch (geen regelnummers)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Aangepaste code-navigatie" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Commando specificeren om code-navigatie te gebruiken, '%f' zal vervangen " +"worden door de bestandsnaam, '%l' door het regelnummer en '%c' door het " +"kolomnummer." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Hoofdvenster" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "Pad naar een bestand met lekonderdrukkingsregels in het LSAN-formaat." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Heaptrack gegevens openen" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Dit veld specificeert het primaire heaptrack gegevensbestand. Deze " +"bestanden hebben namen als heaptrack.$APP.$PID.gz of heaptrack." +"$APP.$PID.zst. U kunt zo'n bestand produceren door uw toepassing te " +"profileren, bijv. via:

\n" +"
heaptrack <uwtoepassing> ...
\n" +"

Of, als alternatief, kunt u een actief proces via

\n" +"
heaptrack --pid $(pidof <uwtoepassing>)
" +"aankoppelen
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "pad/naar/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"U kunt optioneel een tweede heaptrack gegevensbestand specificeren om " +"mee te vergelijken. Indien ingesteld, zal dit bestand gebruikt worden als " +"een basis en zijn kosten worden afgetrokken van de primaire kosten van " +"gegevens." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profiel&gegevens:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Vergelijken met:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Onderdrukkingen:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "pad/naar/lsan_onderdrukkingen.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Samenvatting" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Lijst met functies die het meeste geheugen alloceerde op een gegeven moment." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Bijdragen aan piek" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lijst met functies die het meeste geheugen lekten." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Grootste gelekt geheugen" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lijst met functies die het vaakst geheugen alloceerde." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Meeste geheugenallocaties" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Lijst met functies die de meeste tijdelijke geheugenallocaties produceerden." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Meeste tijdelijke allocaties" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Onderdrukkingen" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Van onderaan af" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "op functie filteren..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "op bestand filteren..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "op module filteren..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Aanroeper / Aangeroepene" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Van boven naar beneden" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Flame-grafiek" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tapels" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Geselecteerde stapel:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Bestand" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "I&nstellingen" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "allocaties samenvoegen... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "totaal" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B tot 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B tot 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B tot 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B tot 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B tot 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B tot 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B tot 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B tot 1KiB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "meer dan 1KiB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "gegevens worden opnieuw ontleed" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "gegevens worden ontleed" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 gepasseerd: %2/%3 verbruikt: %4 resterend: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "allocaties samenvoegen..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "histogram met afmetingen bouwen..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "grafiek bouwen..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Het aantal keren dat een allocatiefunctie is aangeroepen vanuit deze " +"locatie." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Het aantal tijdelijke allocaties. Deze allocaties worden direct gevolgd " +"door een vrijgave zonder enige andere allocatie er tussendoor." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"De bijdragen uit een locatie aan het maximaal gebruikte heap-geheugen in " +"bytes. Dit neemt deallocaties in rekening." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"De locatie waar vanaf een allocatiefunctie is aangeroepen. " +"Functiesymbool en bestandsinformatie kan onbekend zijn wanneer " +"debuginformatie ontbrak toen heaptrack werd uitgevoerd." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" in %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "bijdragen aan piek: %1 (%2% van totaal)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "gelekt: %1 (%2% van totaal)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "gealloceerd: %1 (%2% van totaal)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "tijdelijk: %1 (%2% van allocaties, %3% van totaal)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "aangeroepen vanuit één locatie" +msgstr[1] "aangeroepen vanuit %1 locatie" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% uit totaal van %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (zelf): %2
  %4% uit totaal van %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusief): %2
  %4% uit totaal van %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbool: %1
binair: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 in %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 allocaties van %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 in %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbool" + +#~ msgid "Binary" +#~ msgstr "Binair" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "De hogere functie die een allocatiefunctie heeft aangeroepen. Kan " +#~ "niet-opgelost zijn wanneer debug-informatie ontbreekt." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "De module, dwz. uitvoerbaar programma of gedeelde bibliotheek, " +#~ "waaruit een allocatiefunctie is aangeroepen." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "De functienaam van de %1. Kan niet-opgelost zijn wanneer debug-informatie " +#~ "ontbreekt." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "De naam van het programma waarin het symbool zich bevindt." + +#~ msgid "Function" +#~ msgstr "Functie" + +#~ msgid "Module" +#~ msgstr "Module" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "De hogere functie die een allocatiefunctie heeft aangeroepen. Kan " +#~ "onbekend zijn wanneer debug-informatie ontbreekt." + +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " in %2" + +#~ msgid "File" +#~ msgstr "Bestand" + +#~ msgid "Line" +#~ msgstr "Lijn" + +#~ msgid "Allocated (Self)" +#~ msgstr "Gealloceerd (zelf)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Gealloceerd (incl.)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Het bestand waar de allocatiefunctie vanaf is aangeroepen. Kan leeg " +#~ "zijn wanneer debug-informatie ontbreekt." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Het regelnummer waar de allocatiefunctie vanaf is aangeroepen. Kan " +#~ "leeg zijn wanneer debug-informatie ontbreekt." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "De som van alle bytes die direct gealloceerd zijn vanaf deze locatie, " +#~ "deallocaties genegeerd." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "De inclusieve som van alle bytes die gealloceerd zijn vanaf deze " +#~ "locatie, deallocaties genegeerd." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " op %2:%3\n" +#~ " in %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inclusief: gealloceerd %1 over %2 aanroepen (%3 tijdelijk, dwz. %4%), " +#~ "piek op %5, gelekt %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "zelf: gealloceerd %1 over %2 aanroepen (%3 tijdelijk, dwz. %4%(, piek op " +#~ "%5, gelekt %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Gealloceerd geheugen" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 in totaal gealloceerd na %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "%2 toegekend na %3 van:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Toont het totale gealloceerde geheugen in de tijd. Deze waarde " +#~ "negeert deallocaties en meet alleen doorloop van heap allocaties." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) gealloceerd in %3 en eronder." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 bijdrage in piekgebruik" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 gealloceerd in totaal" + +#~ msgid "Allocated" +#~ msgstr "Gealloceerd" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Een waarschuwingsgrafiek over het totale geheugen gealloceerd door " +#~ "functies in uw code. Dit aggregeert alle allocatie van geheugens en " +#~ "negeert deallocaties." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 allocaties van %2 op %3:%4 in %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
totaal gealloceerde bytes (negeren van deallocaties):
" +#~ "%1 (%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lijst met functies die het in totaal het meeste geheugen alloceerde, met " +#~ "negeren van deallocaties." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Meest gealloceerd geheugen" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "De som van alle bytes die gealloceerd zijn vanaf deze locatie, " +#~ "deallocaties genegeerd." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "gealloceerd: %1 (%2% van totaal)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Uitvoerbestand van Heaptrack openen" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Gegevensbestanden van Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Grafieken" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "gealloceerd %1 over %2 aanroepen(%3 tijdelijk, dwz. %4%(, piek op %5, " +#~ "gelekt %6" + +#~ msgid "debuggee: %1" +#~ msgstr "debuggee: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "totale uitvoeringstijd: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 op %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Toewijzingen [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Tijdelijke toekenningen [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Gelekt [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Gealloceerd [B]" + +#~ msgid "time in ms" +#~ msgstr "tijd in ms" + +#~ msgid "memory heap size" +#~ msgstr "grootte van geheugenheap" diff --git a/po/nn/heaptrack.po b/po/nn/heaptrack.po new file mode 100644 index 00000000..fb736e3a --- /dev/null +++ b/po/nn/heaptrack.po @@ -0,0 +1,1324 @@ +# Translation of heaptrack to Norwegian Nynorsk +# +# Karl Ove Hufthammer , 2018, 2020, 2023. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-09-05 00:47+0000\n" +"PO-Revision-Date: 2023-08-24 21:38+0200\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +# Merknad til omsettinga av programmet: Programskaparen brukar mykje liten forbokstav der det er meir naturleg med stor. Har derfor endra det til stor i omsettinga. +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Karl Ove Hufthammer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "karl@huftis.org" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Område" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Reserveringar (sjølv)" + +# Talet på reserveringar, derfor fleirtalsform. +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Mellombelse (sjølv)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Topp (sjølv)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Leke (sjølv)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Reserveringar (inkl.)" + +# Talet på reserveringar, derfor fleirtalsform. +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Mellombelse (inkl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Topp (inkl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Leke (inkl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Foreldersymbolet som kalla ein reserverings­funksjon. Funksjons­namnet kan " +"vera ukjent dersom det manglar feilsøkingsinformasjon." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Kor mange gongar ein reserverings­funksjon vart kalla direkte frå dette " +"området." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Talet på direkte minnereserveringar. Desse reserveringane vart direkte " +"kalla av avreserveringar, utan nokon andre reserveringar innimellom." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Maks heap-minne, målt i byte, brukt av reserveringar som kjem frå dette " +"området. Dette tek omsyn til avreserveringar." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Bytane som vart reserverte direkte her og som ikkje vart avreserverte." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Inklusive gongar ein reserveringsfunksjon var kalla frå dette området " +"eller frå andre funksjonar kalla frå området." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Talet på inklusive mellombelse minnereserveringar. Desse reserveringane " +"vart direkte kalla av ei avreservering, utan nokon andre reserveringar " +"innimellom." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Inklusivt maks heap-minne, målt i byte, brukt av reserveringar som kjem " +"frå dette området eller frå funksjonar kalla frå området. Dette tek omsyn " +"til avreserveringar." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Bytane som vart reserverte her og som ikkje vart avreserverte." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Kallar" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Kalla" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Topp" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Leke" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Reserveringar" + +# Talet på reserveringar, derfor fleirtalsform. +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Mellombelse" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Kor %1 er. Funksjons­namnet kan vera ukjent dersom det manglar " +"feilsøkingsinformasjon." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Kjeldekodelinja som kalla ein reserveringsfunksjon. Kan vera ukjend " +"dersom det manglar feilsøkingsinformasjon." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Minnereserveringar" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Minne brukt" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Mellombelse reserveringar" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tid gått" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Minnereserveringar til saman" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Minneforbruk til saman" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Mellombelse reserveringar til saman" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 byte)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "Til saman %1 reserveringar etter %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "Til saman %1 mellombelse reserveringar etter %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "Til saman %1 brukt etter %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 reserveringar etter %3 frå:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 mellombelse reserveringar etter %3 frå:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 brukt etter %3 frå:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Eksporter som …" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Vis forklaring" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Vis graf for totalkostnad" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Vis detaljert kostnadsgraf" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Stabla diagram:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrer inn på utval" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Fjern filter" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Lagra %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Punktbilete (*.png *.jpg *.tiff);;Vektorbilete (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Klarte ikkje lagra biletet til %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "StartSluttDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tid%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Brukt%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Reserveringar%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Mellombelse reserveringar%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Vis bruk av heap-minne over tid.
Trykk og dra for å velja eit " +"tidsområde for filtrering.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Viser talet på minnereserveringar over tid.
Trykk og dra for å velja " +"eit tidsområde for filtrering.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Viser talet på mellombelse minnereserveringar over tid. Ei mellombels " +"reservering er ei reservering som vert følgd direkte av ei avreservering, " +"utan nokon andre reserveringar i mellomtida.
Trykk og dra for å velja eit " +"tidsområde for filtrering.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrert frå %2 til %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (filtrert delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Trykk og dra for å velja eit tidsområde for filtrering." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, brukt: %2. Trykk og dra for å velja eit tidsområde for filtrering." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, reserveringar: %2. Trykk og dra for å velja eit tidsområde for " +"filtrering." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, mellombelse reserveringar: %2. Trykk og dra for å velja eit " +"tidsområde for filtrering." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 reserveringar til saman" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 mellombelse reserveringar til saman" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 topp for minnebruk" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 leke til saman" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2 %) reserveringar i %3 og nedanfor." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2 %) mellombelse reserveringar i %3 og nedanfor." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2 %) bidrag til toppbruk i %3 og nedanfor." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2 %) leke i %3 og nedanfor." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Minnetopp" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "Vis flammegraf over bidrag til heap-minnebruk-toppen til programmet." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Vis flammegraf over leken heap-minne til programmet. Minne vert rekna som " +"leke dersom det aldri vart avreservert." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Vis flammegraf over talet på reserveringar utløyste av funksjonar i " +"programkoden." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Vis flammegraf over talet på mellombelse reserveringar utløyste av " +"funksjonar i programkoden. Reserveringar vert merkte som mellombelse når dei " +"vert direkte etterfølgde av tilhøyrande avreserveringar." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Vel datakjelda som skal visualiserast i flammegrafen." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Nedanfrå og opp-vising" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Bruk nedanfrå og opp-vising av flammegrafen. Når det ikkje er kryssa av her, " +"vert standardvisinga (ovanfrå og ned) brukt i staden for." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Fald saman rekursjonar" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Fald saman stabelrammer for funksjonar som kallar seg sjølve. Når det ikkje " +"er kryssa av her, vert rekursive rammer viste for seg sjølve." + +# Må vera etterfølgjande mellomrom for å ikkje krasja med talet som kjem etterpå. +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Kostnadsgrense: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Kostnadsgrensa definerer ei relativ grense for at element skal takast " +"med. Element med relativ kostnad under denne grensa vert ikkje viste i " +"flammegrafen. Dette vert gjort for å kunna teikna opp grafar for store " +"datasett raskt og med lite minnebruk. Viss du treng fleire detaljar, reduser " +"kostnadsgrensa, eventuelt heilt ned til null." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Søk …" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Søkjer i flammegrafen etter eit symbol." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Tilbakestill visinga" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Vis kallar / kalla" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "Lagar flammegraf …" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2 % av til saman %3) reserveringar i samsvar med søket." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2 % av til saman %3) i samsvar med søket." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack-grensesnitt" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Visualiseringsprogram for data frå «heaptrack»-verktøyet." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "© 2015 Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Opphavsperson og vedlikehaldar" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Grunnprofildata som andre filer skal samanliknast med." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Filer som skal opnast" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FIL …]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Førespurd reserveringsstorleik" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Talet på reserveringar" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Opna fil i skriveprogram" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
Feilsøkt:
%1 (vedlagd)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
Feilsøkt:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
Køyretid til saman:
%1, filtrert frå %2 til %3 (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
Køyretid til saman:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
Systemminne til saman:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
Kall til reserveringsfunksjonar:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
Mellombelse reserveringar:
%1 (%2 %, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
Topp for heap-minnebruk:
%1 etter %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
Topp-RSS (medrekna heaptrack-tillegg):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
Minnebruk-delta:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
Minne leke til saman:
%1 (%2 undertrykt)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
Minne leke til saman:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Klarte ikkje tolka fila %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Brukt" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Storleikar" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Inndataa %1 finst ikkje." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Inndataa %1 er ikkje ei fil." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Inndataa %1 er ikkje lesbare." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Opnar fila %1. Vent litt …" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack – %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack – %1 samanlikna med %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Tolkar fil på nytt. Vent litt …" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Kodenavigering" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Tilpassa …" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatisk (utan linjenummer)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Tilpassa kodenavigering" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Vel kommando som skal brukast til kodenavigering. Plasshaldaren «%f» vert " +"bytt ut med filnamnet, «%l» med linjenummeret og «%c» med kolonnenummeret." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Hovudvindauge" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Opna Heaptrack-data" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Dette feltet definerer hovuddatafil frå heaptrack. Desse filene har " +"filnamn heaptrack.$PROGRAM.$PID.gz eller heaptrack.$PROGRAM." +"$PID.zst. Du kan laga slike filer ved å profilera eit program, for " +"eksempel slik:

\n" +"
heaptrack <programmet-ditt> …
\n" +"

Du kan òg kopla heaptrack til ein prosess som køyrer:

\n" +"
heaptrack --pid $(pidof <programmet-ditt>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "adresse/til/heaptrack.$PROGRAM.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Du kan òg velja ei anna heaptrack-datafil å samanlikna fila med. Fila " +"vert då brukt som grunnlag, og kostnaden hennar vert trekt vekk frå " +"kostnaden til hovudfila." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profil&data:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Samanlikna med:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Undertrykking:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "adresse/til/lsan_undertrykking.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Samandrag" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Oversikt over funksjonane som reserverte mest minne på éin gong." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Bidrag til topp" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Oversikt over funksjonane som lak mest minne." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Største minnelekkasjar" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Oversikt over funksjonane som oftast reserverte minne." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Flest minnereserveringar" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Oversikt over funksjonane som produserte dei fleste minnereserveringane." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Flest mellombelse reserveringar" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Undertrykkingar" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Nedanfrå og opp" + +# Står som bakgrunnstekst i søkjefelt. Ingen grunn til liten forbokstav. +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "Filtrer etter funksjon …" + +# Står som bakgrunnstekst i søkjefelt. Ingen grunn til liten forbokstav. +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "Filtrer etter fil …" + +# Står som bakgrunnstekst i søkjefelt. Ingen grunn til liten forbokstav. +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "Filtrer etter modul …" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Kallar / kalla" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Ovanfrå og ned" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Flammegraf" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Stablar" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Vald stabel:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Fil" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "&Innstillingar" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "Slår saman reserveringar … %1 %" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "Til saman" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0 B til 8 B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9 B til 16 B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17 B til 32 B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33 B til 64 B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65 B til 128 B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129 B til 256 B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257 B til 512 B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 B til 1 KiB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "Meir enn 1 KiB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "tolkar data på nytt" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "tolkar data" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 runde: %2/%3 brukt: %4 att: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "Slår saman reserveringar …" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "Lagar storleikshistogram …" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "Lagar diagram …" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Tilbakelogg" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Kor mange gongar ein reserveringsfunksjon vart kalla frå området." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Talet på mellombelse minnereserveringar. Desse reserveringane vart " +"direkte etterfølgde av tilhøyrande avreserveringar, utan nokon andre " +"reserveringar i mellomtida." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Bidraga frå eit gjeve område til maks heap-minnebruk, målt i byte. Dette " +"tek omsyn til avreserveringar." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Området som reserverings­funksjonen vart kalla frå. Funksjonssymbol og " +"filinformasjon kan vera ukjende dersom det mangla feilsøkingsinformasjon då " +"heaptrack vart køyrd." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" i %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "Toppbidrag: %1 (%2 % av totalen)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "Leke: %1 (%2 % av totalen)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "Reserveringar: %1 (%2 % av totalen)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "Mellombelse: %1 (%2 % av alle reserveringar, %3 % av totalen)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Tilbakelogg:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "Kalla frå eitt område" +msgstr[1] "Kalla frå %1 område" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4 % av totalt %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (sjølv): %2
  %4 % av totalt %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inklusiv): %2
  %4 % av totalt %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbol: %1
programfil: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 i %2" + +# Alternativ kunne vore «ikkje-funnen», men dette er kortare, finare og i praksis like presist. +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/pl/heaptrack.po b/po/pl/heaptrack.po new file mode 100644 index 00000000..81fd7c3f --- /dev/null +++ b/po/pl/heaptrack.po @@ -0,0 +1,1603 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Łukasz Wojniłowicz , 2015, 2016, 2017, 2018, 2019, 2021, 2023. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-04-23 12:38+0200\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Łukasz Wojniłowicz" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "lukasz.wojnilowicz@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Położenie" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Przydziały (własne)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Tymczasowe (własne)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "W szczycie (własne)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Wycieki (własne)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Przydziały (inkluzywne)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Tymczasowe (inkluzywne)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "W szczycie (inkluzywne)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Wycieki (inkluzywne)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Symbol nadrzędny, która wywołała funkcję przydzielania. Nazwa funkcji " +"będzie nierozwiązana, gdy będzie brakować danych diagnostycznych." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Liczba razy bezpośredniego wywołania funkcji przydzielającej z tego " +"położenia." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Liczba bezpośrednich tymczasowych przydziałów. Po tych przydziałach " +"bezpośrednio następuje zwolnienie bez dodatkowych przydziałów w między " +"czasie." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Największa liczba bajtów pamięci stosu zajętych przez przydziały " +"bezpośrednio z tego położenia. Liczba ta uwzględnia zwolnienie przydziału." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Bajty bezpośrednio przydzielone w tym położeniu, które nie zostały " +"zwolnione." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Inkluzywna liczba razy wywołania funkcji przydzielającej z tego " +"położenia lub dowolnych funkcji wywołanych z tego miejsca." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Liczba inkluzywnych tymczasowych przydziałów. Po tych przydziałach " +"bezpośrednio następuje zwolnienie bez dodatkowych przydziałów w między " +"czasie." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Największa liczba bajtów pamięci stosu zajętych przez przydziały z tego " +"miejsca lub przez funkcje wywołane z tego miejsca. Liczba ta uwzględnia " +"zwolnienie przydziału." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Bajty przydzielone w tym położeniu, które nie zostały zwolnione." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Wywołujący" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Wywoływany" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Szczyt" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Wycieki" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Przydziały" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Tymczasowy" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Położenie %1. Nazwa funkcji może być nierozwiązana, gdy będzie brakować " +"danych diagnostycznych." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Miejsce w kodzie źródłowym, w którym wywołano funkcję przydzielania. " +"Będzie nieznana, gdy brakuje danych diagnostycznych." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Przydziałów pamięci" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Pochłonięta pamięć" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Tymczasowe przydziały" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Czas działania" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Łącznie przydzieleń pamięci" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Łączne wykorzystanie pamięci" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Łącznie przydzieleń tymczasowych" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bajtów)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 przydzieleń w całości po %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 tymczasowych przydzieleń w całości po %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 wykorzystano razem po %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 przydziałów po %3 od:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 tymczasowych przydziałów po %3 od:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 wykorzystano po %3 od:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Wyeksportuj jako..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Pokaż legendę" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Pokaż graf łącznych kosztów" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Pokaż szczegółowy graf kosztów" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Skumulowane diagramy:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Odfiltruj na zaznaczeniu" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Wyzeruj filtr" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Zapisz %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Obraz rastrowy (*.png *.jpg *.tiff);;Obraz wektorowy (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Nie udało się zapisać obrazu do %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "PoczątekKoniecDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Czas%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Wykorzystanie%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Przydziały%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Tymczasowe przydziały%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Pokazuje wykorzystanie stosu pamięci na osi czasu.
Naciśnij i " +"przeciągnij, aby określić zakres czasu do filtrowania.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Pokazuje liczbę przydzieleń pamięci na osi czasu.
Naciśnij i " +"przeciągnij, aby określić zakres czasu do filtrowania.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Wyświetla liczbę tymczasowych przydziałów na osi czasu. Po tych " +"przydziałach bezpośrednio następuje zwolnienie bez dodatkowych przydziałów w " +"między czasie.
Naciśnij i przeciągnij, aby określić zakres czasu do " +"filtrowania.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (odfiltrowane od %2 do %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta odfiltrowanych)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Naciśnij i przeciągnij, aby określić zakres czasu do filtrowania." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Spożytkowane: %2. Naciśnij i przeciągnij, aby określić zakres czasu " +"do filtrowania." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Przydzielenia: %2. Naciśnij i przeciągnij, aby określić zakres czasu " +"do filtrowania." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Tymczasowe przydzielenia: %2. Naciśnij i przeciągnij, aby określić " +"zakres czasu do filtrowania." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 przydzieleń w całości" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 tymczasowych przydzieleń w całości" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "szczytowe wykorzystanie pamięci %1" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 wycieków łącznie" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) przydzieleń w %3 i poniżej." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) tymczasowych przydzieleń w %3 i poniżej." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) udział w szczytowym wykorzystaniu w %3 i poniżej." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) wycieków w %3 i poniżej." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Szczyty wykorzystania pamięci" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Pokaż wykres płomieniowy udziału względem szczytowego wykorzystania pamięci " +"twojej aplikacji." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Pokaż wykres płomieniowy wycieków pamięci twojej aplikacji. Za wyciek uznaje " +"się pamięć przydzieloną, która nigdy nie zostaje zwolniona." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Pokaż wykres płomieniowy liczb przydzieleń wywołanych przez funkcje w twoim " +"kodzie." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Pokaż wykres płomieniowy liczb tymczasowych przydzieleń wywołanych przez " +"funkcje w twoim kodzie. Przydzielenia są zaliczane do tymczasowych, jeśli " +"zaraz po nich następuje zwolnienie przydziału." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Wybierz źródło danych do zobrazowania na wykresie płomieniowym." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Widok od-dołu-do-góry" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Włącz widok wykresu płomieniowego od dołu do góry. Gdy jest to oznaczone to " +"widokiem domyślnym jest widok od góry do dołu." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Zwiń rekursję" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Zwiń klatki stosów dla funkcji wywołujących same siebie. Gdy odznaczysz to " +"pole, kaltki rekursywne zostaną zobrazowane osobno." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Próg kosztu:" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Próg kosztu określa ułamkową wartość odcinania. Elementy z względnym " +"kosztem poniżej tej wartości nie będą pokazywane na wykresie płomieniowym. " +"Możliwość ta została wprowadzona jako optymalizacja do szybkiego rysowania " +"wykresów dla dużych danych przy niewielkiej ilości pamięci. Jeśli będziesz " +"potrzebował więcej szczegółów, zmniejsz wartość progu lub ustaw ją na zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Znajdź..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Przejrzyj wykres płomieniowy w poszukiwaniu symbolu." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Wyzeruj widok" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Zobacz wywołującego / wywołanego" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "tworzenie wykresu płomieniowego..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% z sumy %3) przydzieleń pasujących do wyszukiwania." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% z sumy %3) pasujących do wyszukiwania." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interfejs Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Obrazowanie dla plików danych heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor pierwszej wersji, opiekun" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Dane profilu podstawowego do porównywania z innymi plikami." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Wczytaj wykaz wygaszonych wycieków z danego pliku. Określ tylko jedno " +"wygaszenie na wiersz i zaczynaj każdy wiersz od słowa 'leak:', tj. używaj " +"formatu pliku wygaszania LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Pomijaj wygaszenia, które są osadzone w pliku danych heaptrack. Domyślnie, " +"heaptrack skopiuje wygaszenia opcjonalnie określone poprzez symbole `const " +"char *__lsan_default_suppressions()` w diagnozowanym programie. Te z kolei " +"będą zawsze stosowane podczas analizowania danych, chyba że jednoznacznie " +"wyłączysz to zachowanie poprzez użycie tego ustawienia wiersza poleceń." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Pomiń definicje wygaszania, które są wbudowane w heaptrack. Domyślnie, " +"heaptrack wygasi pewne znane wycieki w powszechnych bibliotekach systemowych." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Pliki do wczytania" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[PLIK...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 przydziałów z %2, razem %3 przydzielonych ze średnią %4 na przydział" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Żądany rozmiar przydziału" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Liczba przydziałów" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Otwórz plik w edytorze" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
diagnozowany:
" +"%1(dołączony)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
diagnozowany:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
czas działania łącznie:
%1, odfiltrowany od %2 do %3 " +"(%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
całkowity czas działania:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
suma pamięci systemowej:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" +"
wywołania do funkcji przydzielających:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
tymczasowe przydziały:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
szczytowe wykorzystanie pamięci stosu:
%1 po %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
szczytowe RSS (włączając w to narzut heaptracka):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta wykorzystania pamięci:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" +"
łącznie pamięci, która wyciekła:
%1 (%2 wygaszone)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
suma pamięci, która wyciekła:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Nieudane przetwarzanie pliku: %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Pochłonięto" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Rozmiary" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Dane wejściowe %1 nie istnieją." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Dane wejściowe %1 nie są plikiem." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Nie można odczytać danych wejściowych %1." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Nie udało się przetworzyć pliku wygaszonych." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Wyłącz osadzone wygaszenia" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Wyłącz wbudowane wygaszenia" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Pomiń definicje wygaszania, które są wbudowane w heaptrack. Domyślnie, " +"heaptrack wygasi pewne znane wycieki w powszechnych bibliotekach systemowych." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Wczytywanie pliku %1, proszę czekać..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 porównany z %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Ponowne przetwarzanie pliku, proszę czekać..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Poruszanie się po kodzie" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Własne..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Samoczynnie (bez numerów wierszy)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Własne poruszanie się po kodzie" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Podaj polecenie używane do poruszania się po kodzie, '%f' zostanie " +"zastąpione nazwą pliku, '%l' zostanie zastąpione numerem wiersza, a '%c' " +"numerem kolumny." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "GłówneOkno" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Ścieżka do pliku zawierającego zasady wygaszania wycieków w formacie LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Otwórz dane Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

To pole wskazuje na główny plik danych heaptrack. Pliki te nazywają " +"się heaptrack.$APP.$PID.gz lub heaptrack.$APP.$PID.zst. " +"Możesz utworzyć taki plik w trakcie profilowania swojej aplikacji, np. przez:" +"

\n" +"
heaptrack <twoja_aplikacja> ...
\n" +"

Alternatywnie, możesz doczepić się do działającego procesu przez

\n" +"
heaptrack --pid $(pidof <twoja_aplikacja>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "ścieżka/do/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Opcjonalnie możesz podać drugi plik danych heaptrack do porównania. " +"Jeśli tak zrobisz, to plik ten zostanie ustawiony jako podstawa i jego " +"koszty będą odejmowane od kosztów pliku głównego." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dane profilu:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Porównaj z:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Wygaszenia:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "ścieżka/do/wygaszeń_lsan.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Podsumowanie" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Lista funkcji, które przydzieliły najwięcej pamięci w danym czasie." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Udziały szczytowego wykorzystania" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lista funkcji, które spowodowały najwięcej wycieków pamięci." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Największe wycieki pamięci" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lista funkcji, które przydzielały pamięć najszęściej." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Najczęstsze przydzielenia pamięci" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "Lista funkcji, które najczęściej przydzielały pamięć tymczasowo." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Najczęstsze przydzielenia tymczasowe" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Wygaszenia" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Z dołu do góry" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "odfiltruj wg funkcji..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "odfiltruj wg pliku..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "odfiltruj wg modułu..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Wywołujący / Wywołany" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Z góry na dół" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Wykres płomieni" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tosy" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Wybrany stos:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Plik" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Ustawie&nia" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Odfiltruj" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "scalanie przydziałów... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "łącznie" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B do 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B do 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B do 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B do 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B do 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B do 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "25B do 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B do 256B" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "większy niż 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "ponowne przetwarzanie danych" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "przetwarzanie danych" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 przejście: %2/%3 spędzono: %4 pozostało: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "scalanie przydziałów..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "tworzenie histogramu rozmiaru..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "tworzenie wykresów..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Ślad stosu" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Liczba razy wywołania funkcji przydzielającej z tego położenia." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Liczba tymczasowych przydziałów. Po tych przydziałach bezpośrednio " +"następuje zwolnienie bez dodatkowych przydziałów w między czasie." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Udziały z danego miejsca do największego wykorzystania pamięci stosu w " +"bajtach. Liczba ta uwzględnia zwolnienia przydziałów." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Położenie z jakiego została wywołana funkcja. Symbol funkcji i " +"informacje o pliku mogą być nieznane, jeśli brakowało informacji " +"diagnostycznych przed uruchomieniem heaptracka." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" w %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "udział w szczycie: %1 (%2% z całości)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "wycieki: %1 (%2% z całości)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "przydzieleń: %1 (%2% z całości)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "tymczasowych: %1 (%2% z przydzieleń, %3% z całości)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "ślad:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "wywołane z jednego miejsca" +msgstr[1] "wywołane z %1 miejsc" +msgstr[2] "wywołane z %1 miejsc" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% z całkowitej %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (własne): %2
  %4% z całkowitej %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inkluzywne): %2
  %4% z całkowitej %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbol: %1
dwójkowo: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 w %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 przydzieleń z %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 w %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbol" + +#~ msgid "Binary" +#~ msgstr "Dwójkowy" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Funkcja nadrzędna, która wywołała funkcję przydzielania. Będzie " +#~ "nierozwiązana, gdy brakuje informacji diagnostycznych." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Moduł, tj. plik wykonywalny lub biblioteka współdzielona, z której " +#~ "wywołano funkcję przydzielania." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Nazwa funkcji %1. Może być nierozwiązana, gdy będzie brakować danych " +#~ "diagnostycznych." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "Nazwa pliku wykonywalnego, w którym znajduje się symbol." + +#~ msgid "Function" +#~ msgstr "Funkcja" + +#~ msgid "Module" +#~ msgstr "Moduł" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Funkcja nadrzędna, która wywołała funkcję przydzielania. Będzie " +#~ "nieznana, gdy brakuje informacji diagnostycznych." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " w %2" + +#~ msgid "File" +#~ msgstr "Plik" + +#~ msgid "Line" +#~ msgstr "Linia" + +#~ msgid "Allocated (Self)" +#~ msgstr "Przydzielonych (własne)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Przydzielonych (inkluzywne)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Plik, z którego wywołano funkcję przydzielającą. Będzie puste, gdy " +#~ "brakuje informacji diagnostycznych." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Numer wiersza, z którego wywołano funkcję przydzielającą. Będzie " +#~ "puste, gdy brakuje informacji diagnostycznych." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Suma wszystkich bajtów bezpośrednio przydzielonych w tym położeniu, " +#~ "bez uwzględniania zwalniania przydziałów." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Inkluzywna suma wszystkich bajtów przydzielonych w tym miejscu lub " +#~ "funkcji wywołanych z tego miejsca, bez uwzględniania zwalniania " +#~ "przydziałów." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " w %2:%3\n" +#~ " w %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inkluzywne: przydzielono %1 przez %2 wywołań (%3 tymczasowych, tj. %4%), " +#~ "szczyt w %5, wyciekło %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "własne: przydzielono %1 przez %2 wywołań (%3 tymczasowych, tj. %4%), " +#~ "szczyt w %5, wyciekło %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Przydzielonej pamięci" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 przydzieleń w całości po %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 przydzielono po %3 od:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Wyświetla całkowitą przydzieloną pamięć na osi czasu. Ta wartość " +#~ "pomija zwolnienia przydziałów i mierzy tylko przepustowość przydziałów na " +#~ "stosie." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) przydzieleń w %3 i poniżej." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 udział w szczytowym wykorzystaniu" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 przydzieleń w całości" + +#~ msgid "Allocated" +#~ msgstr "Przydzielonych" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Pokaż wykres płomieniowy całkowitej pamięci przydzielonej przez funkcje w " +#~ "twoim kodzie. Sumuje to wszystkie przydziały pamięci i pomija zwolnienie " +#~ "tych przydziałów." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 przydzieleń z %2 w %3:%4 z %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
całkowicie przydzielonych bajtów (pomijając zwolnienia " +#~ "przydziału):
%1 (%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lista funkcji, które przydzieliły najwięcej pamięci w ogólności z " +#~ "pominięciem zwolnień przydziałów." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Najwięcej przydzielonej pamięci" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Suma wszystkich bajtów przydzielonych w tym położeniu, bez " +#~ "uwzględniania zwalniania przydziałów." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "przydzielono: %1 (%2 z całości)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Otwórz plik wynikowy Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Pliki danych Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Grafy" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "przydzielono %1 przez %2 wywołań (%3 tymczasowych, tj. %4%), szczyt w %5, " +#~ "wyciekło %6" + +#~ msgid "debuggee: %1" +#~ msgstr "diagnozowany: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "wyszystkich bibliotek uruchomieniowych: %1s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 o %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Przydziały [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Tymczasowe przydziały [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Wycieki [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Przydzielone [B]" + +#~ msgid "time in ms" +#~ msgstr "czas w ms" + +#~ msgid "memory heap size" +#~ msgstr "rozmiar sterty pamięci" diff --git a/po/pt/heaptrack.po b/po/pt/heaptrack.po new file mode 100644 index 00000000..a4db3d5e --- /dev/null +++ b/po/pt/heaptrack.po @@ -0,0 +1,1369 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-05 11:15+0100\n" +"Last-Translator: José Nuno Coelho Pires \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-POFile-SpellExtra: Wolff heaptrack ms Milian Heaptrack free Incl pid\n" +"X-POFile-SpellExtra: pidof KDevelop Creator gvim gedit Kate KWrite\n" +"X-POFile-SpellExtra: supressões leak LSAN const char\n" +"X-POFile-SpellExtra: lsandefaultsuppressions Supressões supressoeslsan txt\n" +"X-POFile-SpellExtra: jpg tiff\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "José Nuno Pires" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "zepires@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Localização" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Alocações (Próprio)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporário (Próprio)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pico (Próprio)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Fugas (Próprio)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Alocações (Incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporário (Incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pico (Incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Fugas (Incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"O símbolo-pai que invocou uma função de alocação. Poderá não ser " +"possível resolvê-lo se não existir a informação de depuração." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"O número de vezes que uma função de alocação foi invocada directamente a " +"partir deste local." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"O número de alocações temporárias directas. Estas alocações são seguidas " +"directamente de um 'free' (libertação), sem outras alocações intermédias." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"A memória de dados máxima, em 'bytes', consumida em alocações com origem " +"directa neste local. Isto tem as libertações das alocações em conta." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Os 'bytes' alocados directamente neste local que não foram libertados." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"O número de vezes inclusivo que uma função de alocação foi invocada a " +"partir deste local." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"O número de alocações temporárias inclusivas. Estas alocações são " +"seguidas directamente de um 'free' (libertação), sem outras alocações " +"intermédias." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"A memória de dados inclusiva máxima, em 'bytes', consumida em alocações " +"com origem neste local. Isto tem as libertações das alocações em conta." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Os 'bytes' alocados neste local que não foram libertados." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Chamador" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Chamado" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pico" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Fugas" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Alocações" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporário" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"A localização do %1. Poderá não ser possível resolver o nome da função se " +"não existir a informação de depuração." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"A localização no código-fonte que invocou uma função de alocação. Poderá " +"estar em branco se não existir a informação de depuração." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Alocações de Memória" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memória Consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Alocações Temporárias" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tempo Decorrido" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total de Alocações de Memória" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total de Consumo de Memória" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total de Alocações Temporárias" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 alocações no total após o %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 alocações temporárias no total após o %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumidos no total após o %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 alocações após %3 de:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 alocações temporárias após %3 de:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumidos após %3 de:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportar Como..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostrar a legenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostrar o gráfico do custo total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostrar o gráfico do custo detalhado" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagramas empilhados:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrar a Selecção" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Reiniciar o Filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Gravar o %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Imagem Rasterizada (*.png *.jpg *.tiff);;Imagem Vectorial (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Não foi possível gravar a imagem em %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InícioFimDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Hora%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumida%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Alocações%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Alocações Temporárias%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Mostra o consumo de memória de dados ao longo do tempo.
Carregue e " +"arraste para seleccionar um intervalo de tempo na filtragem.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra o número de alocações de memória ao longo do tempo.
Carregue " +"e arraste para seleccionar um intervalo de tempo na filtragem.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra o número de alocações temporárias ao longo do tempo. Estas " +"alocações são seguidas directamente de um 'free' (libertação), sem outras " +"alocações intermédias.
Carregue e arraste para seleccionar um intervalo " +"de tempo na filtragem.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrados de %2 até %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (delta filtrado)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Carregue e arraste para seleccionar o intervalo de tempo na filtragem." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consumida: %2. Carregue e arraste para seleccionar o intervalo de " +"tempo na filtragem." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Alocações: %2. Carregue e arraste para seleccionar o intervalo de " +"tempo na filtragem." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Alocações Temporárias: %2. Carregue e arraste para seleccionar o " +"intervalo de tempo na filtragem." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 alocações no total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 alocações temporárias no total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 de pico de consumo de memória" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 de fugas no total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) alocações em %3 e abaixo." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) alocações temporárias em %3 e abaixo." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "contribuição para o consumo de pico %1 (%2%) em %3 e abaixo." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) de fugas em %3 e abaixo." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pico de Memória" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostrar um gráfico em chama sobre as contribuições para os picos de consumo " +"de memória de dados da sua aplicação." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostrar um gráfico em chama da memória de dados com fugas da sua aplicação. " +"A memória considera-se com fugas se nunca tiver sido libertada. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostrar um gráfico em chama sobre o número de alocações despoletadas por " +"funções no seu código." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostrar um gráfico em chama das alocações temporárias despoletadas por " +"funções da sua aplicação. As alocações são marcadas como temporárias se " +"forem imediatamente seguidas das suas libertações." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Seleccione a fonte de dados que deverá ser visualizada no gráfico em chama." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Vista de Baixo-para-Cima" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Activa a visualização do gráfico em chama de baixo-para-cima. Se estiver " +"desligado, é activada por omissão a vista de cima-para-baixo." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Fechar a Recursividade" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Recolhe as áreas da pilha para as funções que se chamam a si próprias. " +"Quando esta opção estiver desligada, as áreas recursivas da pilha serão " +"visualizadas em separado." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Limiar de Custo: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"O limiar do custo define um valor de corte fraccionário. Os itens com um " +"custo relativo abaixo deste valor não serão apresentados no gráfico em " +"chama. Isto é feito como uma optimização para gerar rapidamente gráficos " +"para conjuntos de dados grandes e com pouca sobrecarga de memória. Se " +"precisar de mais detalhes, diminua o valor-limite ou configure-o como zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Procurar..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Procure no gráfico em chama por um símbolo." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Repor a Janela" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Ver o Chamador/Chamado" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "a gerar o gráfico em chama..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% num total de %3) alocações correspondentes à pesquisa." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% num total de %3) correspondentes à pesquisa." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interface do Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Um visualizador dos ficheiros de dados do 'heaptrack'." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autoria original, manutenção" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Os dados do perfil de base com os quais comparar os outros ficheiros." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Carregar uma lista de supressões de fugas do ficheiro indicado. Indique uma " +"supressão por linha, começando cada linha por 'leak:', i.e. use o formato de " +"ficheiro de supressões LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorar as definições de supressões que estão incorporadas no ficheiro de " +"dados do 'heaptrack'. Por omissão, o 'heaptrack' irá copiar as supressões " +"definidas opcionalmente através de um símbolo `const char " +"*__lsan_default_suppressions()` na aplicação sob depuração. Estas serão " +"sempre aplicadas ao analisar os dados, a menos que esta funcionalidade " +"estejam explicitamente desligada com esta opção da linha de comandos." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorar as definições de supressão compiladas dentro do 'heaptrack'. Por " +"omissão, este irá suprimir certo tipo de fugas conhecidas em algumas " +"bibliotecas comuns do sistema." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Os ficheiros a ler" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FICHEIRO...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 alocações de %2, totalizando %3 alocados com uma média de %4 por alocação" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Tamanho Pedido da Alocação" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Número de Alocações" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Abrir o ficheiro num editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depurado:
%1 " +"(associado)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depurado:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
tempo de execução total:
%1, filtrado de %2 até %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
tempo de execução total:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memória total do sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
chamadas às funções de alocação:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
alocações temporárias:
%1 (%2, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
pico do consumo de memória de dados:
%1 ao fim de %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
RSS de pico (incluindo a sobrecarga do 'heaptrack'):
%1" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta do consumo de memória:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
total da fuga de memória:
%1 (%2 suprimidas)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
total da fuga de memória:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Não foi possível processar o ficheiro %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumida" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Tamanhos" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Os dados de entrada %1 não existem." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Os dados de entrada %1 não são um ficheiro." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Os dados de entrada %1 não são legíveis." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Não foi possível processar o ficheiro de supressões." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Desactivar as Supressões Incorporadas" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Desactivar as Supressões Incorporadas" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorar as definições de supressão compiladas dentro do 'heaptrack'. Por " +"omissão, este irá suprimir certo tipo de fugas conhecidas em algumas " +"bibliotecas comuns do sistema." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "A carregar o ficheiro %1; espere por favor..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 comparado com %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "A processar de novo o ficheiro; espere por favor..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegação pelo Código" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalizar..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automática (Sem Números de Linha)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegação pelo Código Personalizada" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Indique o comando a usar na navegação pelo código; o '%f' será substituído " +"pelo nome do ficheiro, o '%l' pelo número da linha e o '%c' pelo número da " +"coluna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Janela Principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Localização de um ficheiro com regras de supressão de fugas no formato LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Abrir os Dados do Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Este campo define o ficheiro de dados principal do 'heaptrack'. Estes " +"ficheiros são chamados de heaptrack.$APP.$PID.gz. Poderá produzir " +"um destes ficheiros se analisar a performance da sua aplicação, p.ex., com:\n" +"

heaptrack <aplicação> ...
\n" +"

Ou, em alternativa, poder-se-á a associar a um processo em execução com\n" +"

heaptrack --pid $(pidof <aplicação>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "local/do/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Poderá definir opcionalmente um segundo ficheiro de dados do 'heaptrack' " +"para comparação. Se estiver definido, este ficheiro será usado como base e o " +"seu custo será subtraído aos custos dos dados primários." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dados de Performance:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Comparar com:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supressões:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "localização/das/supressoes_lsan.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resumo" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "A lista de funções que alocaram mais memória numa determinada altura." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Contribuições para os Picos" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "A lista das funções que criaram mais fugas de memória." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Maiores Fugas de Memória" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "A lista das funções que alocaram memória com maior frequência." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Mais Alocações de Memória" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"A lista das funções que produziram mais alocações de memória temporária." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Mais Alocações Temporárias" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supressões" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Baixo-para-Cima" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrar pela função..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrar pelo ficheiro..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrar pelo módulo..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Chamador / Chamado" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Cima-Baixo" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Grafo em Chama" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "&Pilhas" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Pilha Seleccionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Ficheiro" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Co&nfiguração" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtro" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "a reunir as alocações... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "mais de 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "a processar de novo os dados" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "a analisar os dados" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 passado: %2/%3 gasto: %4 falta: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "a reunir as alocações..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "a criar o histograma do tamanho..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "a criar os gráficos..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Registo de Chamadas" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"O número de vezes que uma função de alocação foi invocada a partir deste " +"local." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"O número de alocações temporárias. Estas alocações são seguidas " +"directamente de um 'free' (libertação), sem outras alocações intermédias." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"As contribuições de uma dada localização para o consumo da memória de " +"dados máxima, em 'bytes'. Isto tem as libertações das alocações em conta." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"A localização a partir da qual foi invocada uma função de alocação. A " +"informação dos ficheiros e símbolos das funções poderá ser desconhecida " +"quando não existir dados de depuração no momento em que o 'heaptrack' foi " +"executado." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" em %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "contribuições para os picos: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "com fugas: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "alocações: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporárias: %1 (%2% das alocações, %3% do total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "registo de chamadas:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "chamado a partir de um local" +msgstr[1] "chamado a partir de %1 locais" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% de um total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (próprio): %2
  %4% de um total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inclusivo): %2
  %4% de um total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbolo: %1
binário: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 em %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" diff --git a/po/pt_BR/heaptrack.po b/po/pt_BR/heaptrack.po new file mode 100644 index 00000000..505ff577 --- /dev/null +++ b/po/pt_BR/heaptrack.po @@ -0,0 +1,1571 @@ +# Translation of heaptrack.po to Brazilian Portuguese +# Copyright (C) 2015-2016 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# André Marcelo Alvarenga , 2015, 2016. +# Luiz Fernando Ranghetti , 2017, 2018, 2019, 2020, 2021, 2022, 2023. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-05-31 14:33-0300\n" +"Last-Translator: Luiz Fernando Ranghetti \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 21.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "André Marcelo Alvarenga" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "alvarenga@kde.org" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Localização" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Alocações (próprio)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Temporário (próprio)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Pico (próprio)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Vazamento (próprio)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Alocações (Incl.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Temporário (Incl.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Pico (Incl.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Vazamento (Incl.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"O símbolo-pai que chamou uma função de alocação. O nome da função poderá " +"não estar resolvido se não existir informações de depuração." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"O número de vezes que uma função de alocação foi chamada diretamente a " +"partir deste local." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Número de alocações temporárias diretas. Estas alocações são seguidas " +"diretamente de um 'free' (libertação), sem outras alocações intermediárias." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"A memória de dados máxima, em bytes, consumida em alocações com origem " +"direta neste local. As desalocações são consideradas." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Os bytes alocados diretamente neste local que não foram desalocados." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"O número de vezes abrangente que uma função de alocação foi chamada a " +"partir deste local." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Número de alocações temporárias abrangentes. Estas alocações são " +"seguidas diretamente de um 'free' (libertação), sem outras alocações " +"intermediárias." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"A memória de dados abrangente máxima, em bytes, consumida em alocações " +"com origem neste local ou de funções chamada a partir daqui. As desalocações " +"são consideradas." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Os bytes alocados neste local que não foram desalocados." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Chamador" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Chamado" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Pico" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Vazamento" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Alocações" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Temporário" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"A localização de %1. O nome da função poderá não estar resolvido se não " +"existir informações de depuração." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"A localização do código-fonte que chamou uma função de alocação. Poderá " +"estar em branco se não existir informações de depuração." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Alocações de memória" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Memória consumida" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Alocações temporárias" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Tempo decorrido" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total de alocações de memória" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total de consumo de memória" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total de alocações temporárias" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bytes)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 alocações no total após o %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 alocações temporárias no total após o %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 consumidos no total após o %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 alocações após %3 de:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 alocações temporárias após %3 de:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 consumidos após %3 de:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportar como..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Mostrar legenda" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Mostrar gráfico de custo total" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Mostrar gráfico de custo detalhado" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Diagramas empilhados:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrar na seleção" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Redefinir filtro" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Salvar %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Imagem raster (*.png *.jpg *.tiff);;Imagem vetorial (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Falha ao salvar a imagem em %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "InícioFimDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Hora%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Consumido%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Alocações%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Alocações temporárias%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Mostra o consumo de memória de dados ao longo do tempo.
Clique e " +"arraste para selecionar uma faixa de tempo para filtrar.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Mostra o número de alocações de memória ao longo do tempo
Clique e " +"arraste para selecionar uma faixa de tempo para filtrar.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Mostra o número de alocações de memória temporárias ao longo do tempo. " +"Estas alocações são seguidas diretamente de uma desalocação correspondente, " +"sem outras alocações intermediárias.
Clique e arraste para selecionar uma " +"faixa de tempo para filtrar.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrados de %2 para %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (filtrados delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Clique e arraste para selecionar uma faixa de tempo para filtrar." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Consumido: %2. Clique e arraste para selecionar uma faixa de tempo " +"para filtrar." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Alocações: %2. Clique e arraste para selecionar uma faixa de tempo " +"para filtrar." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Alocações temporárias: %2. Clique e arraste para selecionar uma " +"faixa de tempo para filtrar." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 alocações no total" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 alocações temporárias no total" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 pico de consumo de memória" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 vazamentos no total" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) alocações em %3 e abaixo." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) alocações temporárias em %3 e abaixo." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) contribuições para o picos de consumo em %3 e abaixo." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) vazamentos em %3 e abaixo." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pico de memória" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Mostrar um gráfico em chama sobre as contribuições para o pico de consumo de " +"memória do seu aplicativo." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Mostrar um gráfico em chama dos vazamentos da memória de dados do seu " +"aplicativo. A memória que nunca foi desalocada é considerada com vazamento." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Mostrar um gráfico em chama sobre o número de alocações acionadas por " +"funções no seu código." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Mostrar um gráfico em chama das alocações temporárias acionadas por funções " +"do seu código. As alocações são marcadas como temporárias se forem " +"imediatamente seguidas das suas desalocações." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Selecione a fonte de dados que deverá ser visualizada no gráfico em chama." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Exibição de baixo para cima" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Ativa a visualização do gráfico em chama de baixo para cima. Se estiver " +"desmarcada, a visualização de cima-para-baixo será ativada por padrão." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Recolher recursivamente" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Recolhe os quadros de pilha para funções que se chamam. Quando isto " +"édesmarcados, os quadros recursivos serão visualizados separadamente." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Limite de custo: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"O limite do custo define um valor de corte fracionário. Os itens com um " +"custo relativo abaixo deste valor não serão apresentados no grafo em chama. " +"Isto é feito como uma otimização para gerar grafos rapidamente para " +"conjuntos de dados grandes e com pouca sobrecarga de memória. Se precisar de " +"mais detalhes, diminua o valor limite ou defina-o como zero." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Pesquisar..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Pesquisa o gráfico em chamas por um símbolo." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Redefinir exibição" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Exibição do chamador/chamado" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "gerando grafo em chama..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% do total de %3) alocações correspondem a pesquisa." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% do total de %3) correspondem a pesquisa." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Interface do heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Um visualizador dos arquivos de dados do heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Autor original e mantenedor" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Dados do perfil base para comparar a outros arquivos." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Carrega a lista de vazamentos suprimidos de um arquivo especificado. " +"Especifique uma supressão por linha e comece cada linha com 'leak', ou seja, " +"use o formato de arquivo de supressão LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorar as definições de supressão que são embutidas no arquivo de dados do " +"heaptrack. Por padrão, o heaptrack irá copiar as supressões opcionalmente " +"definidas pelo símbolo 'const char *__lsan_default_suppressions()' no " +"aplicativo depurado. Estes são então sempre aplicados ao analisar os dados, " +"a menos queeste recurso seja explicitamente desabilitado usando esta opção " +"de linha de comando." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorar as definições de supressão que são integradas no heaptrack. Por " +"padrão, o heaptrack irá suprimir certos vazamentos em bibliotecas de sistema " +"comuns." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Arquivos a carregar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[ARQUIVO...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 alocações de %2, totalizando %3 alocações com uma média de %4 por alocação" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Tamanho solicitado para a alocação" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Número de alocações" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Abrir arquivo no editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
depurado:
%1 (anexo)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
depurado:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
tempo de execução total:
%1, filtrado de %2 para %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
tempo de execução total:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
memória total do sistema:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" +"
chamadas para as funções de alocação:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
alocações temporárias:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" +"
pico do consumo de memória de dados:
%1 após %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
pico RSS (incluindo sobrecarga do heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta do consumo de memória:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" +"
total do vazamento de memória:
%1 (%2 suprimidos)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
total do vazamento de memória:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Não foi possível processar o arquivo %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Consumido" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Tamanhos" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "O dado de entrada %1 não existe." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "O dado de entrada %1 não é um arquivo." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "O dado de entrada %1 não pode ser lido." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Não foi possível processar o arquivo de supressão." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Desabilitar supressões embutidas" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Desabilitar supressões integradas" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorar as definições de supressão que são integradas no heaptrack. Por " +"padrão, o heaptrack irá suprimir certos vazamentos para bibliotecas de " +"sistema comuns." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Carregando o arquivo %1, aguarde..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 comparado a %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Reanalisando arquivo, aguarde..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Navegação de código" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Personalizado..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automático (sem número de linhas)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Navegação de código personalizada" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Especifique o comando a usar para a navegação do código, '%f' será " +"substituído pelo nome do arquivo, '%l' pelo número da linha e '%c' pelo " +"número da coluna." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Janela principal" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Caminho para o arquivo que contém as regras de supressão de vazamentos no " +"formato LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Abrir dados do heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Este campo especifica o arquivo de dados heaptrack primário. Estes " +"arquivos são chamados heaptrack.$APP.$PID.gz ou heaptrack.$APP." +"$PID.zst. Você pode produzi-los ao analisar seu aplicativo, por exemplo " +"via:

\n" +"
heaptrack <seuaplicativo> ...
\n" +"

Ou, alternativamente, você pode anexar a um processo em execução via

\n" +"
heaptrack --pid $(pidof <seuaplicativo>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "caminho/para/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Você pode opcionalmente especificar um segundo arquivo de dados " +"heaptrack para comparar. Se marcado, este arquivo será usado como base e seu " +"custo será subtraído do custo do dado primário." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Dados do perfil:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Comparar com:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Supressões:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "caminho/para/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Resumo" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Lista de funções que alocaram mais memória em determinado momento." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Picos de contribuições" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lista das funções que criaram mais vazamentos de memória." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Maiores vazamentos de memória" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lista das funções que alocaram memória com maior frequência." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Mais alocações de memória" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "Lista das funções que produziram mais alocações de memória temporária." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Mais alocações temporárias" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Supressões" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Baixo-para-cima" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrar por função..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrar por arquivo..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrar por módulo..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Chamador/chamado" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "De cima para baixo" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Grafo em chama" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "Pil&has" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Pilha selecionada:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Arquivo" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Co&nfigurações" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filtro" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "mesclando as alocações...%1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "total" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B a 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B a 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B a 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B a 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B a 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B a 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B a 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B a 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "mais de 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "reanalisando dados" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "analisando dados" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 passou: %2/%3 gasto: %4 restante: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "mesclando as alocações..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "criando o histograma do tamanho..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "criando os gráficos..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"O número de vezes que uma função de alocação foi chamada deste local." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Número de alocações temporárias. Estas alocações são seguidas " +"diretamente de um 'free' (libertação), sem outras alocações intermediárias." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"As contribuições de um determinado local para a memória de dados máxima " +"consumida em bytes. As desalocações são consideradas." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"A localização da qual foi chamada uma função de alocação. A informação " +"dos arquivos e símbolos das funções poderá ser desconhecida quando não " +"existir informações de depuração no momento em que o heaptrack foi executado." +"" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" em %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "pico de contribuição: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "vazamentos: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "alocações: %1 (%2% do total)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "temporárias: %1 (%2% das alocações, %3% do total)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "chamado de um local" +msgstr[1] "chamado de %1 locais" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% de um total de %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (próprio): %2
  %4% de um total de %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (abrangente): %2
  %4% de um total de %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "símbolo: %1
executável: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 em %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 alocações de %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 em %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Símbolo" + +#~ msgid "Binary" +#~ msgstr "Executável" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "A função-mãe que chamou uma função de alocação. Poderá não estar " +#~ "resolvido se não existir informações de depuração." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "O módulo, que pode ser um executável ou biblioteca dinâmica, onde foi " +#~ "chamada a função de alocação." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "O nome da função de %1. Poderá não estar resolvido se não existir " +#~ "informações de depuração." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "O nome do executável que contém o símbolo." + +#~ msgid "Function" +#~ msgstr "Função" + +#~ msgid "Module" +#~ msgstr "Módulo" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "A função-mãe que chamou uma função de alocação. Poderá estar em " +#~ "branco se não existir informações de depuração." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " em %2" + +#~ msgid "File" +#~ msgstr "Arquivo" + +#~ msgid "Line" +#~ msgstr "Linha" + +#~ msgid "Allocated (Self)" +#~ msgstr "Alocado (Próprio)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Alocado (Incl.)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "O arquivo onde foi chamada a função de alocação. Poderá estar em " +#~ "branco se não existir informações de depuração." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "O número da linha onde foi chamada a função de alocação. Poderá estar " +#~ "em branco se não existir informações de depuração." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "A soma de todos os bytes diretamente alocados nesta região, ignorando " +#~ "as desalocações." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "A soma abrangente de todos os bytes alocados neste local ou de " +#~ "funções chamadas a partir daqui, ignorando as desalocações." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " em %2:%3\n" +#~ " no %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "abrangente: foram alocados %1 em %2 chamadas (%3 temporárias, isto é, " +#~ "%4%), com um pico de %5 e com vazamentos de %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "próprio: foram alocados %1 em %2 chamadas (%3 temporárias, isto é, %4%), " +#~ "com um pico de %5 e com vazamentos de %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Memória alocada" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 alocado no total após o %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "%2 alocados após %3 de:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Mostra a memória total alocada ao longo do tempo. Este valor ignora " +#~ "as desalocações de memória, medindo apenas a taxa de alocação da memória " +#~ "de dados." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) alocados em %3 e abaixo." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 contribuição para o pico de consumo" + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 alocados no total" + +#~ msgid "Allocated" +#~ msgstr "Alocado" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Mostrar um gráfico em chama sobre a memória total alocada pelas funções " +#~ "do seu código. Isto agrega todas as alocações de memória e ignora as " +#~ "desalocações." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 alocações de %2 em %3:%4 em %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
total de bytes alocados (ignorando as desalocações):
" +#~ "%1 (%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lista das funções que alocaram mais memória de forma global, ignorando as " +#~ "desalocações de memória." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Mais memória alocada" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "A soma de todos os bytes alocados nesta região, ignorando as " +#~ "desalocações." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "alocado: %1 (%2 do total)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Abrir o arquivo de saída do Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Arquivos de dados do Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Gráficos" diff --git a/po/ru/heaptrack.po b/po/ru/heaptrack.po new file mode 100644 index 00000000..2cd954eb --- /dev/null +++ b/po/ru/heaptrack.po @@ -0,0 +1,1544 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Alexander Potashev , 2015, 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2017-09-14 15:13+0300\n" +"Last-Translator: Alexander Potashev \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Александр Поташев" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "aspotashev@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Место" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Allocations (Self)" +msgstr "Выделения" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Temporary (Self)" +msgstr "Выделения" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, fuzzy, kde-format +#| msgid "Leaked" +msgid "Peak (Self)" +msgstr "Объём утечки" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, fuzzy, kde-format +#| msgid "Leaked" +msgid "Leaked (Self)" +msgstr "Объём утечки" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Allocations (Incl.)" +msgstr "Выделения" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Temporary (Incl.)" +msgstr "Выделения" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, fuzzy, kde-format +#| msgid "Leaked" +msgid "Peak (Incl.)" +msgstr "Объём утечки" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, fuzzy, kde-format +#| msgid "Leaked" +msgid "Leaked (Incl.)" +msgstr "Объём утечки" + +#: gui/callercalleemodel.cpp:63 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, fuzzy, kde-format +#| msgid "" +#| "The maximum heap memory in bytes consumed from allocations " +#| "originating at this location. This takes deallocations into account." +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Максимальный объём использованной памяти, затребованной всеми операциями " +"выделения из указанного места. Операции освобождения памяти учитываются и " +"уменьшают данное значение." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, fuzzy, kde-format +#| msgid "" +#| "The bytes allocated at this location that have not been deallocated." +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "Объём памяти, выделенной в указанном месте, но не очищенной." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, fuzzy, kde-format +#| msgid "" +#| "The maximum heap memory in bytes consumed from allocations " +#| "originating at this location. This takes deallocations into account." +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Максимальный объём использованной памяти, затребованной всеми операциями " +"выделения из указанного места. Операции освобождения памяти учитываются и " +"уменьшают данное значение." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Объём памяти, выделенной в указанном месте, но не очищенной." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, fuzzy, kde-format +#| msgid "Peak [B]" +msgid "Peak" +msgstr "Пик [Б]" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Объём утечки" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Выделения" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Temporary" +msgstr "Выделения" + +#: gui/callercalleemodel.h:170 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/callercalleemodel.h:356 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/chartmodel.cpp:52 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Memory Allocations" +msgstr "Выделения" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Объём занятой памяти" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Временные выделения" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "" + +#: gui/chartmodel.cpp:83 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Total Memory Allocations" +msgstr "Выделения" + +#: gui/chartmodel.cpp:85 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Total Memory Consumption" +msgstr "Выделения" + +#: gui/chartmodel.cpp:87 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Total Temporary Allocations" +msgstr "Выделения" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "" + +#: gui/chartmodel.cpp:174 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 allocations in total after %2" +msgstr "Выделения" + +#: gui/chartmodel.cpp:176 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 temporary allocations in total after %2" +msgstr "Выделения" + +#: gui/chartmodel.cpp:178 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 consumed in total after %2" +msgstr "Выделения" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "Выделения" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, fuzzy, kde-format +#| msgid "filter by function..." +msgid "Filter In On Selection" +msgstr "Фильтр по функциям..." + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, fuzzy, kde-format +#| msgid "calls to allocation functions: %1 (%2/s)" +msgid "" +"Temporary Allocations%1%2%3" +msgstr "Вызовов функций выделения памяти: %1 (%2/с)" + +#: gui/chartwidget.cpp:441 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/chartwidget.cpp:445 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/chartwidget.cpp:449 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/chartwidget.cpp:471 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "Выделения" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 allocations in total" +msgstr "Выделения" + +#: gui/flamegraph.cpp:177 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 temporary allocations in total" +msgstr "Выделения" + +#: gui/flamegraph.cpp:179 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "%1 peak memory consumption" +msgstr "Выделения" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, fuzzy, kde-format +#| msgid "Allocations" +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "Выделения" + +#: gui/flamegraph.cpp:239 +#, fuzzy, kde-format +#| msgid "Allocations" +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "Выделения" + +#: gui/flamegraph.cpp:244 +#, fuzzy, kde-format +#| msgid "Allocations" +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "Выделения" + +#: gui/flamegraph.cpp:248 +#, fuzzy, kde-format +#| msgid "Allocations" +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "Выделения" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, fuzzy, kde-format +#| msgid "Bottom-Up" +msgid "Bottom-Up View" +msgstr "Вызовы" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Графический интерфейс к Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Визуализатор файлов данных из программы heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "© Milian Wolff , 2015" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Первоначальный автор и сопровождающий" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Открываемый файл" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[файл...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Requested Allocation Size" +msgstr "Выделения" + +#: gui/histogramwidget.cpp:105 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Number of Allocations" +msgstr "Выделения" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "Объём утечки памяти: %1" + +#: gui/mainwindow.cpp:406 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
total runtime:
%1
" +msgstr "Объём утечки памяти: %1" + +#: gui/mainwindow.cpp:408 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
total system memory:
%1
" +msgstr "Объём утечки памяти: %1" + +#: gui/mainwindow.cpp:415 +#, fuzzy, kde-format +#| msgid "calls to allocation functions: %1 (%2/s)" +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "Вызовов функций выделения памяти: %1 (%2/с)" + +#: gui/mainwindow.cpp:418 +#, fuzzy, kde-format +#| msgid "calls to allocation functions: %1 (%2/s)" +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "Вызовов функций выделения памяти: %1 (%2/с)" + +#: gui/mainwindow.cpp:428 +#, fuzzy, kde-format +#| msgid "peak heap memory consumption: %1" +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "Пиковое потребление памяти из пула: %1" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, fuzzy, kde-format +#| msgid "peak heap memory consumption: %1" +msgid "
memory consumption delta:
%1
" +msgstr "Пиковое потребление памяти из пула: %1" + +#: gui/mainwindow.cpp:439 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "Объём утечки памяти: %1" + +#: gui/mainwindow.cpp:442 +#, fuzzy, kde-format +#| msgid "total memory leaked: %1" +msgid "
total memory leaked:
%1
" +msgstr "Объём утечки памяти: %1" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Занято" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Размеры" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Идёт загрузка файла %1..." + +# BUGME: please remove "Heaptrack" from here, it's already mentioned in window title --aspotashev +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "%1" + +# BUGME: please remove "Heaptrack" from here, it's already mentioned in window title --aspotashev +#: gui/mainwindow.cpp:687 +#, fuzzy, kde-format +#| msgctxt "%1: file name that is open" +#| msgid "Heaptrack - %1" +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "%1" + +#: gui/mainwindow.cpp:703 +#, fuzzy, kde-format +#| msgid "Loading file %1, please wait..." +msgid "Reparsing file, please wait..." +msgstr "Идёт загрузка файла %1..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr "" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +# BUGME: notr please --aspotashev +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "MainWindow" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, fuzzy, kde-format +#| msgid "Open Heaptrack Output File" +msgid "Open Heaptrack Data" +msgstr "Открытие файла данных Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, fuzzy, kde-format +#| msgid "Heaptrack" +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Most Memory Allocations" +msgstr "Выделения" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "Most Temporary Allocations" +msgstr "Выделения" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Вызовы" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "Фильтр по функциям..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "Фильтр по файлам..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "Фильтр по модулям..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Файл" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "merging allocations... %1%" +msgstr "Выделения" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0-8 Б" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9-16 Б" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17-32 Б" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33-64 Б" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65-128 Б" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129-256 Б" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257-512 Б" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 Б - 1 КБ" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "более 1 КБ" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "merging allocations..." +msgstr "Выделения" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, fuzzy, kde-format +#| msgid "backtrace:" +msgid "Backtrace" +msgstr "Стек вызовов:" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/treemodel.cpp:83 +#, fuzzy, kde-format +#| msgid "" +#| "The number of times an allocation function was called from this " +#| "location." +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Число вызовов функции выделения, совершённых из указанного места." + +#: gui/treemodel.cpp:87 +#, fuzzy, kde-format +#| msgid "" +#| "The maximum heap memory in bytes consumed from allocations " +#| "originating at this location. This takes deallocations into account." +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Максимальный объём использованной памяти, затребованной всеми операциями " +"выделения из указанного места. Операции освобождения памяти учитываются и " +"уменьшают данное значение." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Место, из которого была вызвана функция выделения памяти. Если во время " +"работы heaptrack отладочная информация была недоступна, то имена функций и " +"файлов не смогут быть показаны." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "Выделения" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "allocations: %1 (%2% of total)\n" +msgstr "Выделения" + +#: gui/treemodel.cpp:162 +#, fuzzy, kde-format +#| msgid "Allocations" +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "Выделения" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "Стек вызовов:" + +#: gui/treemodel.cpp:180 +#, fuzzy, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "Вызывается в %1 месте" +msgstr[1] "Вызывается в %1 местах" +msgstr[2] "Вызывается в %1 местах" +msgstr[3] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#, fuzzy +#~| msgid "Heaptrack" +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "Heaptrack" + +#, fuzzy +#~| msgid "Allocations" +#~ msgid "%1 allocations from %2" +#~ msgstr "Выделения" + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "Location" +#~ msgid "Function" +#~ msgstr "Место" + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Self)" +#~ msgstr "Выделено" + +#, fuzzy +#~| msgid "Allocated" +#~ msgid "Allocated (Incl.)" +#~ msgstr "Выделено" + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "" +#~| "The number of times an allocation function was called from this " +#~| "location." +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Число вызовов функции выделения, совершённых из указанного места." + +#, fuzzy +#~| msgid "" +#~| "The sum of all bytes allocated from this location, ignoring " +#~| "deallocations." +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Суммарный объём памяти, выделенной в указанном месте, без учёта " +#~ "освобождения памяти." + +#, fuzzy +#~| msgid "" +#~| "The sum of all bytes allocated from this location, ignoring " +#~| "deallocations." +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Суммарный объём памяти, выделенной в указанном месте, без учёта " +#~ "освобождения памяти." + +#, fuzzy +#~| msgid "Allocations" +#~ msgid "Memory Allocated" +#~ msgstr "Выделения" + +#, fuzzy +#~| msgid "Allocations" +#~ msgid "%1 allocated in total after %2" +#~ msgstr "Выделения" + +#, fuzzy +#~| msgid "Allocations" +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "Выделения" + +#, fuzzy +#~| msgid "Allocations" +#~ msgid "%1 allocated in total" +#~ msgstr "Выделения" + +#~ msgid "Allocated" +#~ msgstr "Выделено" + +#, fuzzy +#~| msgid "" +#~| "bytes allocated in total (ignoring deallocations): %1 " +#~| "(%2/s)" +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "Суммарный объём выделенной памяти (не включая " +#~ "освобождения): %1 (%2/с)" + +#, fuzzy +#~| msgid "Allocations" +#~ msgid "Most Memory Allocated" +#~ msgstr "Выделения" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Суммарный объём памяти, выделенной в указанном месте, без учёта " +#~ "освобождения памяти." + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Открытие файла данных Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Файлы данных Heaptrack (heaptrack.*)" + +#~ msgid "debuggee: %1" +#~ msgstr "Отлаживаемая программа: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "Полное время работы: %1 с" + +#~ msgid "Allocations [-]" +#~ msgstr "Число выделений" + +#, fuzzy +#~| msgid "Allocations [-]" +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Число выделений" + +#~ msgid "Leaked [B]" +#~ msgstr "Утечка [Б]" + +#~ msgid "Allocated [B]" +#~ msgstr "Выделено [Б]" + +#~ msgid "time in ms" +#~ msgstr "Время в мс" + +#~ msgid "memory heap size" +#~ msgstr "Объём памяти в пуле" diff --git a/po/sk/heaptrack.po b/po/sk/heaptrack.po new file mode 100644 index 00000000..6bb0cbda --- /dev/null +++ b/po/sk/heaptrack.po @@ -0,0 +1,1575 @@ +# translation of heaptrack.po to Slovak +# Roman Paholik , 2015, 2016, 2017. +# Mthw , 2019. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2019-01-28 18:52+0100\n" +"Last-Translator: Mthw \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 18.12.1\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Roman Paholík" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "wizzardsk@gmail.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Umiestnenie" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Alokácie (vlastné)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Dočasné (vlastné)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Vrch (vlastné)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Uniknuté (vlastné)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Alokácie (vrátane)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Dočasné (vrátane)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Vrch (vrátane)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Uniknuté (vrátane)" + +#: gui/callercalleemodel.cpp:63 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, ak " +"chýbajú ladiace informácie." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "Koľko krát sa alokačná funkcia volala z tohto miesta." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Počet priamych dočasných alokácií. Tieto alokácie môžu priamo nasledovať " +"uvoľnenia bez alokácií medzi nimi." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Maximálna pamäť haldy v bajtoch spotrebovaná alokáciami z tohto miesta. " +"Berie do úvahy dealokácie." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Bajty alokované priamo z tohto miesta, ktoré neboli dealokované. " + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Kompletný počet koľkokrát bola alokačná funkia volaná z tohto miesta " +"alebo ľubovoľné funkcie volané odtiaľto." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Počet celkových dočasných alokácií. Tieto alokácie priamo nasleduje " +"uvoľnenie bez iných alokácií medzi tým." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Celková maximálna pamäť haldy v bajtoch spotrebovaná z alokácií z tohto " +"miesta alebo z funkcií z tohto miesta. Berie do úvahy dealokáce." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Bajty alokované na tomto mieste, ktoré neboli dealokované." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Volajúci" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Volaný" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Vrch" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Uniknuté" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Alokácie" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Dočasné" + +#: gui/callercalleemodel.h:170 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, ak " +"chýbajú ladiace informácie." + +#: gui/callercalleemodel.h:356 +#, fuzzy, kde-format +#| msgid "" +#| "The parent function that called an allocation function. May be " +#| "unknown when debug information is missing." +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, ak " +"chýbajú ladiace informácie." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Alokácie pamäte" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Spotrebovaná pamäť" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Dočasné alokácie" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Uplynutý čas" + +#: gui/chartmodel.cpp:83 +#, fuzzy, kde-format +#| msgid "Most Memory Allocations" +msgid "Total Memory Allocations" +msgstr "Najviac alokácií pamäte" + +#: gui/chartmodel.cpp:85 +#, fuzzy, kde-format +#| msgid "%1 peak memory consumption" +msgid "Total Memory Consumption" +msgstr "%1 vrchol spotreby pamäte" + +#: gui/chartmodel.cpp:87 +#, fuzzy, kde-format +#| msgid "Most Temporary Allocations" +msgid "Total Temporary Allocations" +msgstr "Najviac dočasných alokácií" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bajtov)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 alokácií celkovo po %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 dočasných alokácií celkovo po %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 spotrebované celkovo po %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 alokácií po %3 od:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 pamäťových alokácií po %3 od:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 spotrebované po %3 od:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, fuzzy, kde-format +#| msgid "filter by function..." +msgid "Filter In On Selection" +msgstr "filtrovať podľa funkcie..." + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, fuzzy, kde-format +#| msgid "Reset View" +msgid "Reset Filter" +msgstr "Znovunastaviť pohľad" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to save the image to %1" +msgstr "Zlyhalo spracovanie súboru %1." + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, fuzzy, kde-format +#| msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgid "" +"Temporary Allocations%1%2%3" +msgstr "
dočasné alokácie:
%1 (%2%, %3/s)
" + +#: gui/chartwidget.cpp:441 +#, fuzzy, kde-format +#| msgid "Shows the heap memory consumption over time." +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "Zobrazí spotebu pamäte haldy v čase." + +#: gui/chartwidget.cpp:445 +#, fuzzy, kde-format +#| msgid "Shows number of memory allocations over time." +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "Zobrazí počet pamätových alokácií v čase. " + +#: gui/chartwidget.cpp:449 +#, fuzzy, kde-format +#| msgid "" +#| "Shows number of temporary memory allocations over time. A temporary " +#| "allocation is one that is followed immediately by its corresponding " +#| "deallocation, without other allocations happening in-between." +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Zobrazí počet dočasných pamäťových alokácií v čase. Dočasná alokácie je " +"taká, ktorá je nasledovaná dealokáciou bez iných alokáci medzi nimi." + +#: gui/chartwidget.cpp:471 +#, fuzzy, kde-format +#| msgid "%1 allocations from %2 in %3 (%4)" +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 alokácií od %2 v %3 (%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 alokácií celkovo" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 dočasných alokácií celkovo" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 vrchol spotreby pamäte" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 celkovo uniknutých" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) alokácií v %3 a menej." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) dočasných alokácií v %3 a menej." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) príspevok do vrcholnej spotreby v %3 a nižšie." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) uniknuté v %3 a menej." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Pamäťový vrchol" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Zobraziť plamenný graf cez príspevky vrcholu spotreby pamäte haldy vašej " +"aplikácie." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Zobraziť plamenný graf cez uniknutý pamäť haldy vašej aplikácie. Pamäť sa " +"považuje za uniknutú, keď sa nikdy neuvoľní." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Zobraziť plamenný graf cez počet alokácií spustených funkciami vo vašom kóde." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Zobraziť plamenný graf cez počet dočasných alokácií spustených funkciami vo " +"vašom kóde. Alokácie sú označené ako dočasné, keď ihneď nasleduje ich " +"dealokácia." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Vybrať zdroj údajov, ktorý sa má vizualizovať v plamennom grafe." + +#: gui/flamegraph.cpp:467 +#, fuzzy, kde-format +#| msgid "Bottom-Down View" +msgid "Bottom-Up View" +msgstr "Podľad dolu" + +#: gui/flamegraph.cpp:468 +#, fuzzy, kde-format +#| msgid "" +#| "Enable the bottom-down flame graph view. When this is unchecked, the top-" +#| "down view is enabled by default." +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Povoliť spodný-dolný podľad plamenného grafu. Ak je odznačené, predvolene je " +"povolený pohľad vrch-spodok." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Zbaliť rekurziu" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Zbaliť snímky stohov pre funkcie volajúce seba. Ak je odznačené, rekurzívne " +"snímky sa budú vizualizovať oddelene." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Rozptyl ceny: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Cenový prah definuje desatinnú hodnotu. Položky s relatívnou cenou pod " +"tohto hodnotou sa nezobrazia v plamennom grafe. Toto sa robí ako " +"optimalizácia na rýchle vygenerovanie grafov pre veľké dátové sady s malými " +"pamäťovými zdvihmi. Ak potrebujete viac detailov, znížte hodnotu prahu alebo " +"ju nastavte na nulu." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Hľadať..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Hľadať symbol v plamennom grafe." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Znovunastaviť pohľad" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Zobraziť Volajúci/volaný" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "generujem plamenný graf..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% z celkovo %3) alokácií vyhovuje hľadaniu." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% z celkovo %3) vyhovuje hľadaniu." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack GUI" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Vizualizátor pre dátové súbory Heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Pôvodný autor, správca" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Údaje základného profilu na porvnanie ostatných súborov." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Súbory na načítanie" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[SÚBOR...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Vyžadovaná veľkosť alokácie" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Počet alokácií" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Otvoriť súbor v editore" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
ladený:
%1 (pripojený)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "
ladený:
%1
" + +#: gui/mainwindow.cpp:401 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
celkový čas behu:
%1s
" + +#: gui/mainwindow.cpp:406 +#, fuzzy, kde-format +#| msgid "
total runtime:
%1s
" +msgid "
total runtime:
%1
" +msgstr "
celkový čas behu:
%1s
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
celková pamäť systému:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
volania alokačných funkcií:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
dočasné alokácie:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, fuzzy, kde-format +#| msgid "
peak heap memory consumption:
%1 after %2s
" +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
vrcholná spotreba pamäte haldy:
%1 po %2s
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
vrchol RSS (vrátane overheadu heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, fuzzy, kde-format +#| msgid "
peak heap memory consumption:
%1 after %2s
" +msgid "
memory consumption delta:
%1
" +msgstr "
vrcholná spotreba pamäte haldy:
%1 po %2s
" + +#: gui/mainwindow.cpp:439 +#, fuzzy, kde-format +#| msgid "
total memory leaked:
%1
" +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
celková uniknutá pamäť:
%1
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
celková uniknutá pamäť:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Zlyhalo spracovanie súboru %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Použité" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Veľkosti" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Vstupné dáta %1 neexistujú." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Vstupné dáta %1 nie sú súbor." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Vstupné dáta %1 nie sú čitateľné." + +#: gui/mainwindow.cpp:597 +#, fuzzy, kde-format +#| msgid "Failed to parse file %1." +msgid "Failed to parse suppression file." +msgstr "Zlyhalo spracovanie súboru %1." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Načítavam súbor %1, prosím čakajte..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 porovnané s %2" + +#: gui/mainwindow.cpp:703 +#, fuzzy, kde-format +#| msgid "Loading file %1, please wait..." +msgid "Reparsing file, please wait..." +msgstr "Načítavam súbor %1, prosím čakajte..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "MainWindow" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Otvoriť údaje Heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, fuzzy, kde-format +#| msgid "" +#| "

This field specifies the primary heaptrack data file. These files " +#| "are called heaptrack.$APP.$PID.gz. You can produce such a file " +#| "by profiling your application, e.g. via:

\n" +#| "
heaptrack <yourapplication> ...
\n" +#| "

Or, alternatively, you can attach to a running process via

\n" +#| "
heaptrack --pid $(pidof <yourapplication>)
" +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Toto pole určuje hlavný dátový súbor heaptrack. Tieto súbory sú " +"pomenované heaptrack.$APP.$PID.gz. Takýto súbor môžete vytvoriť " +"profilovaním vašej aplikácie, teda cez:

\n" +"
heaptrack <vašaaplikácia> ...
\n" +"

Alebo alternatívne môžete pripoiť k bežiacemu procesu cez

\n" +"
heaptrack --pid $(pidvašej <aplikácie>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, fuzzy, kde-format +#| msgid "path/to/heaptrack.$APP.$PID.gz" +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "cesta/ku/heaptrack.$APP.$PID.gz" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Voliteľne môžete určiť druhý heaptrack dátový súbor na porovnanie. Ak je " +"nastavený, tento súbor sa použije ako základ a jeho ceny sa odčítajú od " +"primárnych dátových cien." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Údane profilu:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Porovnať s:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Súhrn" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Zoznam funkcií, ktoré alokovali najviac pamäte v danom čase." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Vrcholové príspevky" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Zoznam funkcií, ktorým uniklo najviac pamäte." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Najväčšie pamätové úniky" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Zoznam funkcií, ktoré alokujú pamäť najčastejšie." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Najviac alokácií pamäte" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Zoznam funkcií, ktoré vytvárajú najviac dočasných pamäťových alokácií. " + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Najviac dočasných alokácií" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Dole-hore" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrovať podľa funkcie..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrovať podľa súboru..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrovať podľa modulu..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Volajúci / volaný" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Hore-dolu" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Plameňový graf" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "Stohy" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Vybraný zásobník" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Súbor" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Nastavenia" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, fuzzy, kde-format +#| msgid "merging allocations..." +msgid "merging allocations... %1%" +msgstr "zlučujem alokácie..." + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "celkom" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B do 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B do 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B do 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B do 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B do 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B do 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B do 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B do 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "viac ako 1KB" + +#: gui/parser.cpp:645 +#, fuzzy, kde-format +#| msgid "parsing data..." +msgid "reparsing data" +msgstr "spracúvam údaje..." + +#: gui/parser.cpp:645 +#, fuzzy, kde-format +#| msgid "parsing data..." +msgid "parsing data" +msgstr "spracúvam údaje..." + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "zlučujem alokácie..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "zostavujem histogram veľkosti..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "zostavujem grafy..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Backtrace" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "Počet volaní alokačnej funkcie z tohto miesta." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Počet dočasných alokáicií. Tieto alokácie priamo nasleduje uvoľnenie bez " +"iných alokácií medzi nimi." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Príspevky z daného miesta do maximálnej spotreby pamäte v bajtoch. Berie " +"do úvahy dealokácie." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Miesto, z ktorého bola volaná alokačná funkcia. Symbol funkcie a " +"informácia o súbore môže byť neznáma, ak chýbali ladiace informácie počas " +"behu heaptracku." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" v %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "vrcholný príspevok: %1 (%2% celkovo)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "uniknuté: %1 (%2% celkovo)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "alokácie: %1 (%2% celkovo)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "dočasné: %1 (%2% alokácií, %3% celkovo)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "backtrace:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "volané z jedného miesta" +msgstr[1] "volané z %1 miest " +msgstr[2] "volané z %1 miest " + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% z %3 celkovo" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (vlastné): %2
  %4% z %3 celkovo" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (vrátane): %2
  %4% z %3 celkovo" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 in %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#, fuzzy +#~| msgid "heaptrack.*.*.gz" +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#, fuzzy +#~| msgid "%1 allocations from %2 in %3 (%4)" +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 alokácií od %2 v %3 (%4)" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 v %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbol" + +#~ msgid "Binary" +#~ msgstr "Binárne číslo" + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, " +#~ "ak chýbajú ladiace informácie." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Modul, napríklad binárka alebo zdieľaná knižnica, z ktorej sa volala " +#~ "alokačná funkcia." + +#, fuzzy +#~| msgid "" +#~| "The parent function that called an allocation function. May be " +#~| "unknown when debug information is missing." +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, " +#~ "ak chýbajú ladiace informácie." + +#~ msgid "Function" +#~ msgstr "Funkcia" + +#~ msgid "Module" +#~ msgstr "Modul" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Rodičovská funkcia, ktorá volala alokačnú funkciu. Môže byť neznáma, " +#~ "ak chýbajú ladiace informácie." + +#, fuzzy +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " v %2" + +#~ msgid "File" +#~ msgstr "Súbor" + +#~ msgid "Line" +#~ msgstr "Riadok" + +#~ msgid "Allocated (Self)" +#~ msgstr "Alokované (vlastné)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Alokované (vrátane)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "nSúbor, odkiaľ bola volaná alokačná funkcia. Môže byť prázdne, ak " +#~ "chýbajú ladiace informácie." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Číslo riadku, odkiaľ bola volaná alokačná funkcia. Môže byť prázdne, " +#~ "ked chýbajú ladiace informácie." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Suma všetkých bajtov priamo alokovaných z tohto miesta, ignorujúc " +#~ "dealokácie." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Celková suma všetkých bajtov alokovaných z tohto miesta alebo funkcií " +#~ "odtiaľto, ignorujúc dealokácie." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " na %2:%3\n" +#~ " v %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inkluzívne: alokované %1 cez %2 volaní (%3 dočasné, teda %4%), vrchol na " +#~ "%5, uniknuté %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "samotné: alokované %1 cez %2 volaní (%3 dočasné, teda %4%), vrchol na %5, " +#~ "uniknuté %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Alokovaná pamäť" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "%1 alokované celkovo po %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "%2 alokované po %3 od:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Zobrazí celkovú pamäť alokovanú v čase. Táto hodnnota ignoruje " +#~ "dealokácie a iba meria priepustnosť alokácie haldy." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) alokované %3 a menej." + +#~ msgid "%1 allocated in total" +#~ msgstr "%1 alokované celkovo" + +#~ msgid "Allocated" +#~ msgstr "Alokované" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Zobraziť plamenný graf cez celkovú pamäť alokovanú funkciami vo vašom " +#~ "kóde. Toto spojí všetky pamäťové alokácie a ignoruje dealokácie." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 alokácií z %2 na %3:%4 v %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
alokované bajty celkovo (ignorujúc dealokácie):
%1 (%2/" +#~ "s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Zoznam funkcií, ktoré alokovali najviac pamäte celkovo, ignorujúc " +#~ "dealokácie." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Najviac alokovanej pamäte" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Suma všetkých bajtov alokovaných z tohto miesta, ignorujúc dealokácie." +#~ "" + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "alokované: %1 (%2% celkovo)\n" + +#~ msgid "&Graphs" +#~ msgstr "Grafy" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 na %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Alokácie [-]" + +#, fuzzy +#~| msgid "Allocations [-]" +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Alokácie [-]" + +#~ msgid "memory heap size" +#~ msgstr "veľkosť pamäte haldy" diff --git a/po/sl/heaptrack.po b/po/sl/heaptrack.po new file mode 100644 index 00000000..0d430ba5 --- /dev/null +++ b/po/sl/heaptrack.po @@ -0,0 +1,1352 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the heaptrack package. +# +# +# Martin Srebotnjak , 2022. +# Matjaž Jeran , 2022. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-06 09:04+0200\n" +"Last-Translator: Matjaž Jeran \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" +"X-Generator: Poedit 3.1.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Martin Srebotnjak" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "miles@filmsi.net" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Mesto" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Dodelitve (sebi)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Začasno (sebi)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Vrhunec (sebe)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Uhajanja (sebi)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Dodelitve (vklj.)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Začasno (vklj.)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Vrhunec (vklj.)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Uhajanja (vklj.)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Nadrejeni simbol, ki je klical funkcijo dodelitve. Ime funkcije je morda " +"nerazrešeno, če manjkajo informacije o razhroščevanju." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Število neposrednih klicev funkcije dodeljevanja neposredno s tega mesta." +"" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Število neposrednih začasnih dodelitev. Tem dodelitvam neposredno sledi " +"sprostitev brez drugih vmesnih dodelitev." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Največji pomnilnik kopice v bajtih, porabljenih iz dodelitev, ki " +"izvirajo neposredno na tem mestu. Pri tem se upoštevajo raz-dodelitve." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Bajti, dodeljeni neposredno na tem mestu, ki niso bili odrazporejeni." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Vključujoče število, kolikokrat je bila funkcija dodelitve klicana s " +"tega mesta ali iz poljubnih funkcij, klicanih odtod." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Število vključujočih začasnih dodelitev. Tem dodelitvam neposredno sledi " +"sprostitev brez drugih vmesnih dodelitev." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Vključujoči največji pomnilnik v bajtih, porabljenih iz dodelitev s " +"poreklom s tega mesta ali iz funkcij, klicanih odtod. Pri tem se upoštevajo " +"preklici dodelitev." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Bajti, dodeljeni na tem mestu, ki niso bili razporejeni." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Klicatelj" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Klicani" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Vrhunec" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Uhajanja" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Dodelitve" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Začasno" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Lokacija %1. Ime funkcije je morda nerešeno, če manjkajo informacije " +"razhroščevanja." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Mesto izvorne kode, ki je klicalo funkcijo dodelitve. Lahko ni znano, " +"kadar manjkajo informacije razhroščevanja." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Dodelitve pomnilnika" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Porabljen pomnilnik" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Začasne dodelitve" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Pretečeni čas" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Skupna dodelitev pomnilnika" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Skupna poraba pomnilnika" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Skupne začasne dodelitve" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bajtov)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 dodelitev skupaj po %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 začasnih dodelitev skupaj po %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 skupaj porabljenega po %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 dodelitev po %3 iz:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 začasnih dodelitev po %3 iz:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 porabljenega po %3 f iz:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Izvozi kot..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Prikaži legendo" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Prikaži graf skupnih stroškov" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Prikaži graf podrobnih stroškov" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Naloženi diagrami:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtriraj v izboru" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Ponastavi filter" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Shrani %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Rastrska slika (*.png *.jpg *.tiff);;Vektorska slika (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Shranjevanje slike na %1 ni uspelo" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr " Začetek KonecDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Čas%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Porabljeno%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Dodelitve%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "Začasne dodelitve%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Prikazuje porabo pomnilnika kopice skozi čas.
Kliknite in povlecite, " +"da izberete časovni obseg za filtriranje.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Prikaže število dodelitev pomnilnika skozi čas.
Kliknite in " +"povlecite, da izberete časovni obseg za filtriranje.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Prikaže število začasnih dodelitev pomnilnika skozi čas. Začasna " +"dodelitev je začasna dodelitev, ki ji takoj sledi ustrezna sprostitev " +"dodelitve, ne da bi se druga dodelitev zgodila vmes.
Kliknite in " +"povlecite, da izberete časovni obseg za filtriranje.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrirano od %2 do %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (filtrirana delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Kliknite in povlecite, da izberete časovni obseg za filtriranje." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Porabljeno: %2. Kliknite in povlecite, da izberete časovni obseg za " +"filtriranje." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Dodelitve: %2. Kliknite in povlecite, da izberete časovni obseg za " +"filtriranje." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Začasne dodelitve: %2. Kliknite in povlecite, da izberete časovni " +"obseg za filtriranje." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 dodelitev skupaj" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 začasnih dodelitev skupaj" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 vrhuncev porabe pomnilnika" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 uhajanj skupaj" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) dodelitev v %3 in pod njim." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) začasnih dodelitev v %3 in pod njim." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) prispevkov k vrhu porabe v %3 in pod njim." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) uhajanj v %3 in pod njim." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Vrhunec pomnilnika" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Pokaže plamenski grafikon nad prispevki za vrh porabe pomnilnika kopice v " +"vašem programu." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Pokaže plamenski grafikon prek izpustov pomnilnika kopice za vaš program. Za " +"izpust pomnilnika šteje, ko dodelitev nikoli ni sproščena. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Pokaže plamenski grafikon nad številom dodelitev, ki jih sprožijo funkcije v " +"kodi." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Pokaže plamenski grafikon nad številom začasnih dodelitev, ki jih sprožijo " +"funkcije v kodi. Dodelitev se označi kot začasna, ko ji takoj sledi njena " +"sprostitev." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" +"Izberite vir podatkov, ki ga želite vizualizirati v plamenskem grafikonu." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Pogled od spodaj navzgor" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Omogočite pogled plamenskega grafikona od spodaj navzgor. Ko to ni mogoče, " +"je pogled od zgoraj navzdol privzeto omogočen." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Strni rekurzijo" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Strni okvirje sklada za funkcije, ki kličejo same sebe. Če to ni potrjeno, " +"se rekurzivni okvirji ponazorijo ločeno." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Prag stroškov: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Prag stroškov določa ulompljeno vrednost porezave. Elementi z relativnim " +"stroškom pod to vrednostjo ne bodo prikazani v plamenskem grafikonu. To se " +"izvede kot optimizacija za hitro ustvarjanje grafikonov za velike nize " +"podatkov z nizkim pomnilnikom za režijske zahteve. Če potrebujete več " +"podrobnosti, zmanjšajte vrednost praga ali jo nastavite na nič." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Poišči ..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Preiščite plamenski graf za simbol." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Ponastavi pogled" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Pokaži klicatelja/klicanega" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "tvorjenje plamenskega grafikona ..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2% od skupaj %3) dodelitev, ki se ujemajo z iskanjem." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% od skupaj %3), ki se ujemajo z iskanjem." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Grafični uporabniški vmesnik Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Vizualizator za podatkovne datoteke heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Izvirni avtor, vzdrževalec" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Osnovni podatki profila za primerjavo z drugimi datotekami." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Nalaganje seznama zatrtih puščanj za navedeno datoteko. Navedite eno " +"zatiranje na vrstico in začnite vsako vrstico z »leak:«, t.j. uporabite " +"obliko datoteke za zatiranje LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Prezrite definicije zatiranja, ki so vdelane v podatkovno datoteko " +"heaptrack. Privzeto bo heaptrack kopiral zatiranja, ki so izbirno " +"opredeljena prek simbola »const char *__lsan_default_suppressions()« v " +"programu za razhroščevanje. Te se nato vedno uporabljajo pri analizi " +"podatkov, razen če je ta funkcija izrecno onemogočena z uporabo te možnosti " +"ukazne vrstice." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Prezri definicije zatiranj, ki so vgrajene v heaptrack. Privzeto bo " +"heaptrack zatrl nekatera znana uhajanja v skupnih sistemskih knjižnicah." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Datoteke za nalaganje" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[DATOTEKA…]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "%1 dodelitev iz %2, skupaj %3 dodeljenih s povprečjem %4 na dodelitev" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Zahtevana velikost dodelitev" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Število dodelitev" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Odpri datoteko v urejevalniku" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
razhroščevanec:
%1 " +"(priloženo)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
razhroščevanec:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
skupni čas izvajanja:
%1, filtrirano od %2 do %3 (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
skupni čas izvajanja:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
skupni sistemski pomnilnik:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
klici funkcij dodelitev:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
začasne dodelitve:
%1 ( %2% , %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
vrh porabe pomnilnika kopice:
%1 po %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
vrh RSS (vključno z režijskimi stroški heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
delta porabe pomnilnika:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
skupno uhajanje pomnilnika:
%1 (%2 zatrto)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
skupno uhajanje pomnilnika:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Razčlenjevanje datoteke %1 ni uspelo." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Porabljeno" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Velikosti" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Vhodni podatki %1 ne obstajajo." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Vhodni podatki %1 niso datoteka." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Vhodni podatki %1 niso berljivi." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Datoteke za zatiranje ni bilo mogoče razčleniti." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Onemogoči vdelana zatiranja" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Onemogoči vgrajena zatiranja" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Prezri definicije zatiranja, ki so vgrajene v heaptrack. Privzeto bo " +"heaptrack zatiral nekatera znana uhajanja iz skupnih sistemskih knjižnic." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Nalaganje datoteke %1, počakajte ..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1, primerjano z %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Ponovno razčlenjevanje datoteke, počakajte ..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Krmarjenje po kodi" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Po meri …" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Samodejno (brez številk vrstic)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Krmarjenje po kodi po meri" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Določite ukaz, ki ga želite uporabiti za krmarjenje po kodi, »%f« bo " +"nadomeščen z imenom datoteke, »%l« s številko vrstice in »%c« s številko " +"stolpca." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Glavno okno" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Pot do datoteke, ki vsebuje pravila za zatiranje uhajanja v obliki LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Odpri podatke o heaptracku" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

V polju je navedena primarna podatkovna datoteka heaptrack. Te " +"datoteke se imenujejo heaptrack.$APP.$PID.gz ali heaptrack.$APP." +"$PID.zst. Takšno datoteko lahko izdelate tako, da profilirate svoj " +"program, npr.

\n" +"
heaptrack <vašprogram> ...
\n" +"

Lahko pa se priključite na tekoči postopek prek

\n" +"
heaptrack --pid $(pidof <vašprogram>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "pot/do/heaptrack.$APP.$PID. {gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Po želji lahko določite drugo podatkovno datoteko heaptrack za " +"primerjavo. Če je nastavljena, bo ta datoteka uporabljena kot osnova in njen " +"strošek se odšteje od primarnih stroškov podatkov." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Po&datki profila:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Primerjaj z:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Zatiranja:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "pot/do/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Povzetek" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Seznam funkcij, ki so dodelile največ pomnilnika v danem času." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Vrh prispevkov" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Seznam funkcij, ki puščajo največ pomnilnika." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Največji izpusti pomnilnika" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Seznam funkcij, ki najpogosteje dodelijo pomnilnik." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Večina dodelitev pomnilnika" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "Seznam funkcij, ki so ustvarile največ začasnih dodelitev pomnilnika." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Večina začasnih dodelitev" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Zatiranja" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Od spodaj navzgor" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtriranje po funkciji ..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtriranje po datoteki ..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtriranje po modulu ..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Klicatelj / klicani" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Od zgoraj navzdol" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Plamenski graf" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&kladi" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Izbrani sklad:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Datoteka" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "&Nastavitve" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "spajanje dodelitev ... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "skupaj" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0 B do 8 B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9 B do 16 B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17 B do 32 B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33 B do 64 B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65 B do 128 B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129 B do 256 B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257 B do 512 B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 B do 1 KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "več kot 1 KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "ponovno razčlenjevanje podatkov" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "razčlenjevanje podatkov" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 podano: %2/%3 porabljeno: %4 preostaja: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "spajanje dodelitev ..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "gradnja histograma velikosti …" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "gradnja grafikonov ..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Povratno sledenje klicev" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "Število klicev funkcije dodelitev s tega mesta." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Število začasnih dodelitev. Tem dodelitvam neposredno sledi sprostitev " +"dodelitve brez drugih vmesnih dodelitev." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Prispevki z danega mesta k največji porabi pomnilnika kopice v bajtih. " +"Pri tem se upoštevajo sprostitve dodelitev." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Mesto, s katerega je bila poklicana funkcija dodelitve. Simbol funkcije " +"in podatki o datoteki so morda neznani, ko so ob zagonu heaptrack manjkali " +"podatki o napakah." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" v %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "vrh prispevka: %1 (%2% od skupnega)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "uhajanja: %1 (%2% vseh)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "dodelitev: %1 (%2% vseh)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "začasno: %1 (%2% dodelitev, %3% vseh)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "zgodovina klicev:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "klicano s/z %1 mesta" +msgstr[1] "klicano s/z %1 mest" +msgstr[2] "klicano s/z %1 mest" +msgstr[3] "klicano s/z %1 mest" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% od skupaj %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (sebe): %2
  %4% od skupaj %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (vključno): %2
  %4% od skupaj %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "simbol: %1
binarno: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 v %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Ustvarjalec Qt" diff --git a/po/sv/heaptrack.po b/po/sv/heaptrack.po new file mode 100644 index 00000000..869e0c6b --- /dev/null +++ b/po/sv/heaptrack.po @@ -0,0 +1,1591 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Stefan Asserhäll , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2023. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-07-30 16:11+0200\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 20.08.1\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Stefan Asserhäll" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "stefan.asserhall@bredband.net" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Plats" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Tilldelningar (egna)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Tillfällig (egen)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Störst (eget)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Läckt (eget)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Tilldelningar (sammanlagda)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Tillfällig (sammanlagt)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Störst (sammanlagt)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Läckt (sammanlagt)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Överliggande funktion som anropade en tilldelningsfunktion. " +"Funktionsnamnet kan vara okänd om avlusningsinformation saknas." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Antal gånger som en tilldelningsfunktion direkt anropades från platsen." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Antal direkta tillfälliga tilldelningar. Dessa minnestilldelningar följs " +"direkt av free utan några andra mellanliggande tilldelningar." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Maximalt antal heap-minne i byte som konsumerades via tilldelningar som " +"direkt hade sitt ursprung från den här platsen. Detta tar hänsyn till " +"frigjort minne." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Byte direkt tilldelade från den här platsen som inte har frigjorts." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Sammanlagt antal gånger som en tilldelningsfunktion anropades från " +"platsen eller någon funktion anropad härifrån." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Sammanlagt antal tillfälliga tilldelningar. Dessa minnestilldelningar " +"följs direkt av free utan några andra mellanliggande tilldelningar." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Maximalt antal heap-minne i byte som konsumerades via tilldelningar som " +"hade sitt ursprung från den här platsen eller från funktioner anropade " +"härifrån. Det tar hänsyn till frigjort minne." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Byte tilldelade för den här platsen som inte har frigjorts." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Den som anropar" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Den som blir anropad" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Störst" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Läckt" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Tilldelningar" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Tillfällig" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Plats för %1. Funktionsnamnet kan sakna upplösning om avlusningsinformation " +"saknas." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Källkodsplatsen där en tilldelningsfunktion anropades. Kan vara okänd om " +"avlusningsinformation saknas." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Minnestilldelningar" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Använt minne" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Tillfälliga tilldelningar" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Förfluten tid" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Total minnestilldelning" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Total minnesanvändning" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Total tillfällig minnestilldelning" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 byte)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "Totalt %1 tilldelningar efter %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "Totalt %1 tillfälliga tilldelningar efter %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "Totalt %1 använt efter %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 tilldelningar efter %3 från:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 tillfälliga tilldelningar efter %3 från:

" +"%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 använt efter %3 från:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Exportera som..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Visa förklaring" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Visa totalt kostnadsdiagram" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Visa detaljerat kostnadsdiagram" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Överlagrade diagram:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Filtrera in enligt markering" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Nollställ filter" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Spara %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Rastreringsbild (*.png *.jpg *.tiff);;Vektorbild (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Misslyckades spara bilden i %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "StartSlutDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Tid%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Använt%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Tilldelningar%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Tillfälliga tilldelningar%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Visar heap-minnesanvändningen över tiden.
Klicka och dra för att " +"välja ett tidsintervall för filtrering.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Visar antal minnestilldelningar över tiden.
Klicka och dra för att " +"välja ett tidsintervall för filtrering.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Visar antal tillfälliga minnestilldelningar över tiden. En tillfällig " +"tilldelning är en som omedelbart följs av motsvarande frigörelse, utan några " +"andra mellanliggande tilldelningar.
Klicka och dra för att välja ett " +"tidsintervall för filtrering.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (filtrerat från %2 till %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (filtrerat delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Klicka och dra för att välja tidsintervall för filtrering." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, använt: %2. Klicka och dra för att välja tidsintervall för " +"filtrering." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, tilldelningar: %2. Klicka och dra för att välja tidsintervall för " +"filtrering." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, tillfälliga tilldelningar: %2. Klicka och dra för att välja " +"tidsintervall för filtrering." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "Totalt %1 tilldelningar" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "Totalt %1 tillfälliga tilldelningar" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 toppanvändning av minne" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "Totalt %1 läckt" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2 %) tilldelningar i och under %3." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2 %) tillfälliga tilldelningar i och under %3." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2 %) bidrag till största användning i och under %3." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2 %) läckt i och under %3." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Minnestopp" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Visa ett flamdiagram över bidrag till största heap-minnesanvändningen i ditt " +"program." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Visa ett flamdiagram med läckt heap-minne i ditt program. Minne anses vara " +"läckt om det aldrig frigörs." + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Visa ett flamdiagram med antal tilldelningar utlösta av funktioner i din kod." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Visa ett flamdiagram med antal tillfälliga tilldelningar utlösta av " +"funktioner i din kod. Tilldelningar markeras som tillfälliga när de " +"omedelbart följs av en frigörelse." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Välj datakällan som ska åskådliggöras i flamdiagrammet." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Nerifrån och uppåt" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Aktivera visning av flamdiagrammet nerifrån och uppåt. När det inte är " +"markerat, aktiveras förvald visning uppifrån och neråt." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Dra ihop rekursion" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Dra ihop anropsposter för funktioner som anropar sig själva. När det inte är " +"markerat, är rekursiva anropsposter visualiserade separat." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Kostnadströskel:" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Kostnadströskeln definierar ett bråkdelsbrytvärde. Objekt med en relativ " +"kostnad lägre än värdet visas inte i flamdiagrammet. Det görs som en " +"optimering för att snabbt skapa diagram för stora datamängder med låg " +"minnesanvändning. Om du behöver mer detaljer, minska tröskelvärdet, eller " +"ställa in det till noll." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Sök..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Sök i efter en symbol i flamdiagrammet." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Återställ vy" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Visa anropare och anropad" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "skapar flamdiagram..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%2 % av totalt %3) tilldelningar matchade sökningen." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2 % av totalt %3) matchade sökningen." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack grafiskt användargränssnitt" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Ett visualiseringsverktyg för Heaptrack-datafiler." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Ursprunglig upphovsman, underhåll" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Profileringsbasdata att jämföra med andra filer." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Läs in lista över undertryckningar av läckor från den angivna filen. Ange " +"en undertryckning per rad, och börja varje rad med 'leak:', dvs. använd LSAN-" +"filformatet för undertryckningar." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ignorera undertryckningsdefinitioner som är inbäddade i Heaptracks datafil. " +"Normal kopierar Heaptrack undertryckningar valfritt definierade via symbolen " +"`const char *__lsan_default_suppressions()` i det avlusade programmet. De " +"används sedan alltid när data analyseras, om inte funktionen explicit " +"inaktiveras genom att använda den här kommandoradsväljaren." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ignorera undertryckningsdefinitioner som är inbyggda i heaptrack. Normalt " +"undertrycker heaptrack vissa kända läckor i vanliga systembibliotek." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Filer att läsa in" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[FIL...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 tilldelningar från %2, totalt %3 tilldelade med medelvärde %4 per " +"tilldelning" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Begärd tilldelningsstorlek" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Antal tilldelningar" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Öppna fil i editor" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
avlusat program:
" +"%1(anslutet)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
avlusat program:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
total körtid:
%1, filtrerad från %2 till %3 (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
total körtid:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
totalt systemminne:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
anrop till tilldelningsfunktioner:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
tillfälliga tilldelningar:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
största heap-minnesanvändning:
%1 efter %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
topp-RSS (inklusive overhead från heaptrack):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
deltaminnesanvändning:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
totalt läckt minne:
%1 (%2 undertryckt)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
totalt läckt minne:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Misslyckades tolka filen %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Använt" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Storlekar" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Indata %1 finns inte." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Indata %1 är inte en fil." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Indata %1 är inte läsbar." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Misslyckades tolka undertryckningsfil." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Inaktivera inbäddade undertryckningar" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Inaktivera inbyggda undertryckningar" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ignorera undertryckningsdefinitioner som är inbyggda i heaptrack. Normalt " +"undertrycker heaptrack vissa kända läckor från vanliga systembibliotek." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Läser in filen %1. Vänta..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 jämförd med %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Tolkar filen igen. Vänta..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Kodnavigering" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Egen..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Automatisk (inga radnummer)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Egen kodnavigering" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Ange kommando för att använda för kodnavigering, '%f' ersätts av filnamnet, " +"'%l' av radnumret och '%c' av kolumnnumret." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Huvudfönster" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Sökväg till en fil som innehåller undertryckningsregler för läckor med LSAN-" +"format." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Öppna Heaptrack-data" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Fältet anger den primära heaptrack-datafilen. Filerna kallas " +"heaptrack.$APP.$PID.gz eller heaptrack.$APP.$PID.zst. Det " +"går att skapa en sådan fil genom att profilera programmet, t.ex. med:

\n" +"
heaptrack <ditt_program> ...
\n" +"

Som alternativ går det att ansluta till en process som kör med:

\n" +"
heaptrack --pid $(pidof <ditt_program>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "sökväg/till/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"En andra heaptrack-datafil att jämföra med kan valfritt anges. Om det " +"görs används den här filen som bas och dess kostnad subtraheras från de " +"primära datakostnaderna." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profilerings&data:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Jämför med:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Undertryckningar:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "sökväg/till/lsan_undertryckningar.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Sammanfattning" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Lista över funktioner som tilldelas mest minne vid ett givet tillfälle." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Största bidrag" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Lista över funktioner som läcker mest minne." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Största minnesläckor" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Lista över funktioner som oftast tilldelas minne." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Flest minnestilldelningar" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Lista över funktioner som skapar flest tillfälliga minnestilldelningar." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Flest tillfälliga tilldelningar" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Undertryckningar" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Nerifrån och upp" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "filtrera enligt funktion..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "filtrera enligt fil..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "filtrera enligt modul..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Anropare och anropad" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Uppifrån och ner" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Flamdiagram" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tackar" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Vald stack:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Arkiv" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "Inställ&ningar" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Filter" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "sammanfogar tilldelningar... %1 %" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "totalt" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0 B till 8 B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9 B till 16 B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17 B till 32 B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33 B till 64 B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65 B till 128 B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129 B till 256 B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257 B till 512 B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512 B till 1 KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "mer än 1 KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "tolkar data igen" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "tolkar data" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 passerade: %2/%3 använda: %4 återstående: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "sammanfogar tilldelningar..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "skapar storlekshistogram..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "skapar diagram..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Bakåtspårning" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" +"Antal gånger som en tilldelningsfunktion anropades från platsen." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Antal tillfälliga tilldelningar. Dessa minnestilldelningar följs direkt " +"av free utan några andra mellanliggande tilldelningar." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Bidragen från en given plats till maximal heap-minnesanvändning i byte. " +"Detta tar hänsyn till frigjort minne." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Platsen som en tilldelningsfunktion anropades från. Funktionssymbol och " +"filinformation kan vara okänd om avlusningsinformation saknades när " +"Heaptrack kördes." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" i %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "toppbidrag: %1 (%2 % av totala minnet)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "läckt: %1 (%2 % av totala minnet)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "tilldelningar: %1 (%2 % av totala minnet)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "tillfälligt: %1 (%2 % av tilldelningar, %3 % av totala minnet)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "bakåtspårning:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "anropade från en plats" +msgstr[1] "anropade från %1 platser" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4 % av totalt %3" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (själv): %2
  %4 % av totalt %3" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (inklusive): %2
  %4 % av totalt %3" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "symbol: %1
binärfil: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 i %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "Kwrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 tilldelningar från %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 i %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Symbol" + +#~ msgid "Binary" +#~ msgstr "Binärprogram" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Överliggande funktion som anropade en tilldelningsfunktion. Kan sakna " +#~ "upplösning om avlusningsinformation saknas." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Modulen, dvs. körbart program eller delat bibliotek, som en " +#~ "tilldelningsfunktion anropades från." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Funktionsnamnet för %1. Kan sakna upplösning om avlusningsinformation " +#~ "saknas." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "Namnet på den körbara fil som symbolen finns i." + +#~ msgid "Function" +#~ msgstr "Funktion" + +#~ msgid "Module" +#~ msgstr "Modul" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Överliggande funktion som anropade en tilldelningsfunktion. Kan vara " +#~ "okänd om avlusningsinformation saknas." + +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " i %2" + +#~ msgid "File" +#~ msgstr "Arkiv" + +#~ msgid "Line" +#~ msgstr "Rad" + +#~ msgid "Allocated (Self)" +#~ msgstr "Tilldelat (eget)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Tilldelat (sammanlagt)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Filen tilldelningsfunktionen anropades från. Kan vara tomt om " +#~ "avlusningsinformation saknas." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Radnumret tilldelningsfunktionen anropades från. Kan vara tomt om " +#~ "avlusningsinformation saknas." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Summan av alla byte direkt tilldelade från den här platsen, utan att " +#~ "ta hänsyn till frigjort minne." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Sammanlagd summa av alla byte tilldelade från den här platsen eller " +#~ "från funktioner anropade härifrån, utan att ta hänsyn till frigjort minne." +#~ "" + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " från %2:%3\n" +#~ " i %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "inklusive: tilldelade %1 med %2 anrop (%3 tillfälliga, dvs. %4 %), störst " +#~ "%5, läckt %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "egna: tilldelade %1 med %2 anrop (%3 tillfälliga, dvs. %4 %), störst %5, " +#~ "läckt %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Tilldelat minne" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "Totalt %1 tilldelningar efter %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 tilldelat efter %3 från:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Visar total minnestilldelning över tiden. Värdet ignorerar frigjort " +#~ "minne och mäter bara genomströmningen av heap-tilldelningar." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2 %) tilldelat i och under %3." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "%1 bidrag till största användning" + +#~ msgid "%1 allocated in total" +#~ msgstr "Totalt %1 tilldelningar" + +#~ msgid "Allocated" +#~ msgstr "Tilldelat" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Visa ett flamdiagram med totalt minne tilldelat av funktioner i din kod. " +#~ "Det kombinerar alla minnestilldelningar och ignorerar frigjort minne." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 tilldelningar från %2 på %3:%4 i %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
totalt antal tilldelade byte (frigjort minne ignorerat):
%1 (%2/s)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Lista över funktioner som oftast tilldelas minne, som ignorerar frigjort " +#~ "minne." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Mest tilldelat minne" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Summan av alla byte tilldelade från den här platsen, utan att ta " +#~ "hänsyn till frigjort minne." + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "tilldelat: %1 (%2 % av totala minnet)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Öppna Heaptrack-utdatafil" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "Heaptrack-datafiler (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Diagram" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "tilldelade %1 med %2 anrop (%3 tillfälliga, dvs. %4 %), störst %5, läckt " +#~ "%6" + +#~ msgid "debuggee: %1" +#~ msgstr "avlusad modul: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "total körtid: %1 s" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 vid %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Tilldelningar [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Tillfälliga tilldelningar [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Läckt [B]" + +#~ msgid "Allocated [B]" +#~ msgstr "Tilldelat [B]" + +#~ msgid "time in ms" +#~ msgstr "tid i ms" + +#~ msgid "memory heap size" +#~ msgstr "heap-minnesstorlek" diff --git a/po/tr/heaptrack.po b/po/tr/heaptrack.po new file mode 100644 index 00000000..5ca3cc7d --- /dev/null +++ b/po/tr/heaptrack.po @@ -0,0 +1,1340 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Emir SARI , 2022. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-05 10:30+0300\n" +"Last-Translator: Emir SARI \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 22.08.1\n" +"X-POOTLE-MTIME: 1502202299.000000\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Emir SARI" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "emir_sari@icloud.com" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Konum" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Ayırmalar (Öz)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Geçici (Öz)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Tavan (Öz)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Sızan (Öz)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Ayırmalar (İçerilen)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Geçici (İçerilen)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Tavan (İçerilen)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Sızan (İçerilen)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Bir ayırma işlevini çağıran üst sembol. Hata ayıklama bilgisi eksik " +"olduğunda işlev adı çözülemeyebilir." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Bu konumdan bir ayırma işlevinin doğrudan çağrıldığı zaman sayısı." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Doğrudan geçici ayırmaların sayısı. Bu ayırmalar, arasında başka bir " +"ayırma olmadan doğrudan bir boşaltma ile izlenir." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Doğrudan bu konumdan kaynaklı ayırmalar tarafından tüketilen en çok " +"yığın belleği (bayt türünden). Bu, geri ayırmaları hesaba katar." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "Geri ayrılmamış olan doğrudan bu konumda ayrılan baytlar." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Bir ayırma işlevinin veya herhangi bir işlevin bu konumdan çağrıldığı " +"içeren zaman sayısı." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"İçeren geçici ayırmaların sayısı. Bu ayırmalar, arasında başka ayırmalar " +"olmadan doğrudan bir boşaltma ile izlenir." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Bu konumdan veya buradan çağrılan işlevlerden kaynaklı ayırmalar " +"tarafından tüketilen içeren en çok yığın belleği (bayt türünden). Bu, geri " +"ayırmaları hesaba katar." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "Geri ayrılmamış olan bu konumda ayrılan baytlar." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Çağrıcı" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Çağrılan" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Tavan" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Sızan" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Ayırmalar" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Geçici" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"%1 konumu. Hata ayıklama bilgisi eksik olduğunda işlev adı çözülemeyebilir." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Bir ayırma işlevi çağıran kaynak kodu. Hata ayıklama bilgisi eksik " +"olduğunda bilinmiyor olabilir." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Bellek Ayırmaları" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Bellek Tüketimi" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Geçici Ayırmalar" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Geçen Süre" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Toplam Bellek Ayırmaları" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Toplam Bellek Tüketimi" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Toplam Geçici Ayırmalar" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 bayt)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%2 sonrası, toplamda %1 ayırma" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%2 sonrası, toplamda %1 geçici ayırma" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%2 sonrası, toplamda %1 tüketildi" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"Şuradan, %3 sonrası %2 ayırma:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%3 sonrası, şuradan %2 geçici ayırma:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" +"%3 sonrası, şuradan %2 tüketildi:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Farklı Dışa Aktar..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Göstergeyi göster" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Toplam maliyet grafiğini göster" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Ayrıntılı maliyet grafiğini göster" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Yığılmış diyagramlar:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Seçimde Süz" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Süzgeci Sıfırla" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Kaydet: %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "Kafes Görseli (*.png *.jpg *.tiff);;Vektör Görseli (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Görsel, %1 konumuna kaydedilemedi" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "BaşlangıçBitişDelta" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Süre%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Tüketilen%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Ayırmalar%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "Geçici Ayırmalar%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Zaman içindeki yığın belleği tüketimini gösterir.
Süzmek için " +"tıklayın ve sürükleyerek bir zaman aralığı seçin.
" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Zaman içindeki bellek ayırma sayısını gösterir.
Süzmek için tıklayın " +"ve sürükleyerek bir zaman aralığı seçin.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Zaman içindeki geçici bellek ayırma sayısını gösterir. Geçici bir " +"ayırma, hemen arkasından ayrılma geri ayrımı ile izleyen ve arasında başka " +"bir ayırma işlemi olmayan bir ayırmadır.
Süzmek için tıklayın ve " +"sürükleyerek bir zaman aralığı seçin.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (%2-%3 konumundan süzüldü, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (süzülen delta)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "Süzme zaman aralığını seçmek için tıklayın ve sürükleyin." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Tüketilen: %2. Süzme zaman aralığını seçmek için tıklayın ve " +"sürükleyin." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T = %1, Ayırmalar: %2. Süzme zaman aralığını seçmek için tıklayın ve " +"sürükleyin." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T = %1, Geçici Ayırmalar: %2. Süzme zaman aralığını seçmek için tıklayın ve " +"sürükleyin." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "Toplamda %1 ayırma" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "Toplamda %1 geçici ayırma" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 tavan bellek tüketimi" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 toplamda sızan" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%3 ve altında %1 (%​%2) ayırma." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%3 ve altında %1 (%​%2) geçici ayırma." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%3 ve altında tavan tüketime %1 (%​%2) katkı." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%3 ve altında %1 (%​%2) sızma." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Bellek Tavanı" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Uygulamanızın tavan yığın bellek tüketimi üzerinden katkıların bir alev " +"grafiğini göster." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Uygulamanızın sızan yığın belleği üzerinden bir alev grafiği göster. Bellek " +"geri ayrılmazsa sızmış olarak kabul edilir. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Kodunuzdaki işlevler tarafından tetiklenen ayırmalar sayısı üzerinden bir " +"alev grafiği göster." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Kodunuzdaki işlevler tarafından tetiklenen geçici ayırmaların bir alev " +"grafiğini göster. Ayırmalar, anında geri ayrılırsa geçici olarak imlenirler." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Alev grafiğinde görselleştirilmesi gereken veri kaynağını seçin." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Aşağıdan Yukarıya Görünüm" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Aşağıdan yukarıya alev grafiği görünümünü etkinleştir. Bu seçilmemişse " +"yukarıdan aşağıya görünüm öntanımlı olarak etkinleştirilir." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Özyinelemeyi Daralt" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Kendilerini çağıran işlevler için yığın çerçevelerini daralt. Bu " +"seçilmemişse özyineli çerçeveler ayrı olarak görselleştirilecektir." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Maliyet Eşiği: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Maliyet eşiği, bir kesirsel kesim değeri tanımlar. Bu değerin altında " +"bir göreceli maliyetli ögeler alev grafiğinde gösterilmezler. Bu, büyük veri " +"kümeleri için hızlıca grafikler oluşturmak için kullanılan ve düşük bellek " +"kullanan bir eniyileme olarak yapılır. Daha fazla ayrıntıya gereksiniminiz " +"varsa eşik değerini düşürün veya sıfır yapın." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Ara..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Alev grafiğinde bir sembol ara." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Görünümü Sıfırla" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Çağıranı/Çağrılanı Görüntüle" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "alev grafiği oluşturuluyor..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "%1 (%​%2/%3) arama tarafından eşleştirilen ayırmalar." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%​%2/%3) arama tarafından eşleştirildi." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack Kullanıcı Arayüzü" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Heaptrack veri dosyaları için bir görselleştirici." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Telif hakkı 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Özgün yazar, bakımcı" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Diğer dosyalarla karşılaştırılacak temel profil verisi." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Belirtilen dosyadan sızma bastırmaları listesini yükle. Satır başına bir " +"bastırma belirtin ve her bir satıra 'leak' ile başlayın; örneğin LSAN " +"bastırma dosya biçimini kullanın." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Heaptrack veri dosyasına gömülü bastırma tanımlarını yok say. Öntanımlı " +"olarak, Heaptrack, hata ayıklanan uygulamada isteğe bağlı bir `const char " +"*__lsan_default_suppressions()` sembolü ile tanımlanan bastırmaları " +"kopyalayacaktır. Sonrasında, özellik açıkça komut satırı seçeneği ile devre " +"dışı bırakılmamışsa bunlar veri çözümlenirken her zaman uygulanırlar." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Heaptrack içine yapılı bastırma tanımlarını yok say. Öntanımlı olarak, " +"Heaptrack, ortak sistem kitaplıklarındaki bilinen sızmaları bastıracaktır." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Yüklenecek dosyalar" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[DOSYA...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "%1/%2 ayırma, toplam %3 ayrılan, ayırma başına ortalama %4" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "İstenen Ayırma Boyutu" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Ayırma Sayısı" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Dosyayı düzenleyicide aç" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
hata ayıklanan:
%1 " +"(iliştirilmiş)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
hata ayıklanan:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "
toplam çalışma süresi:
%1, %2/%3 süzülen (%4)
" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
toplam çalışma süresi:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
toplam sistem belleği:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
ayırma işlevlerine olan çağrılar:
%1 (%2/sn)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
geçici ayırmalar:
%1 (%​%2, %3/sn)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
tavan yığın bellek tüketimi:
%2 sonrası %1
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
tavan RSS (heaptrack ek yükü içerilir):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
bellek tüketim verisi:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
sızan toplam bellek:
%1 (%2 bastırıldı)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
sızan toplam bellek:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "%1 dosyası ayrıştırılamadı." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Tüketilen" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Boyutlar" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Girdi verisi %1, yok." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Girde verisi %1, bir dosya değil." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Girdi verisi %1, okunabilir değil." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Bastırma dosyası ayrıştırılamadı." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Gömülü Bastırmaları Devre Dışı Bırak" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Yapılı Bastırmaları Devre Dışı Bırak" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Heaptrack içine yapılı bastırma tanımlarını yok say. Öntanımlı olarak, " +"Heaptrack, ortak sistem kitaplıklarındaki bilinen sızmaları bastıracaktır." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "%1 dosyası yükleniyor, lütfen bekleyin..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1, %2 ile karşılaştırılıyor" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Dosya yeniden ayrıştırılıyor, lütfen bekleyin..." + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Kod Dolaşımı" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Özel..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Otomatik (Satır numaraları yok)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Özel Kod Dolaşımı" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Kod dolaşımı için kullanılacak komutu belirtin; '%f', dosya adı ile; '%l', " +"satır numarası ile ve '%c', sütun numarası ile değiştirilir." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Ana Pencere" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "LSAN biçiminde sızma bastırma kurallarını içeren bir dosyaya yol." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Heaptrack Verisi Aç" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Bu alan, birincil yığın izleme veri dosyasını belirtir. Bu dosyalar " +"heaptrack.$APP.$PID.gz veya heaptrack.$APP.$PID.zst olarak " +"adlandırılırlar. Böyle bir dosyayı, örneğin uygulamanızı şunun yardımıyla " +"profilleyerek oluşturabilirsiniz:

\n" +"
heaptrack <uygulamanız> ...
\n" +"

Alternatif olarak, çalışan bir süreci şununla iliştirebilirsiniz:

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "heaptrack/yolu/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"İsteğe bağlı olarak karşılaştırılacak ikinci bir heaptrack dosyası " +"belirtebilirsiniz. Ayarlanırsa bu dosya temel olarak kullanılır ve maliyeti " +"birincil veri maliyetlerinden düşülür." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "Profil &Verisi:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Şununla karşılaştır:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Bastırmalar:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "bastırmalar/yolu/lsan_bastırmaları.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Özet" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "Verilen bir zamanda en çok belleği ayıran işlevler listesi." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Tavan Katkılar" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "En çok belleği sızdıran işlevlerin listesi." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "En Büyük Bellek Sızmaları" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Belleği en sık ayıran işlevler listesi." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "En Çok Bellek Ayırmalar" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "En çok geçici bellek ayırmaları üreten işlevlerin listesi." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "En Çok Geçici Ayırmalar" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Bastırmalar" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Yukarıdan Aşağıya" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "işlev ile süz..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "dosya ile süz..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "modül ile süz..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Çağıran/Çağrılan" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Yukarıdan Aşağıya" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Alev Grafiği" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "Yığı&nlar" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Seçili Yığın:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Dosya" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "&Ayarlar" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Süzgeç" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "ayırmalar birleştiriliyor... %​%1" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "toplam" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B'den 8B'ye" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B'den 16B'ye" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B'den 32B'ye" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B&den 64B'ye" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B'den 128B'ye" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B'den 256B'ye" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B'den 512B'ye" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B'den 1KB'ye" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "1KB'den çok" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "veri yeniden ayrıştırılıyor" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "veri ayrıştırılıyor" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 geçen: %2/%3 harcanan: %4 kalan: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "ayırmalar birleştiriliyor..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "boyut histogramı yapılıyor..." + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "çizelgeler yapılıyor..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Geri İz" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "Bir ayırma işlevinin bu konumdan çağrılma sayısı." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Geçici ayırmaların sayısı. Bu ayırmalar, arasında başka bir ayırma " +"olmadan doğrudan boşaltılırlar." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Belirli bir konumdan bayt türünden en yüksek yığın bellek tüketimine " +"katkılar. Bu, ayırmaları hesaba katar." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Bir ayırma işlevinin çağrıldığı konum. İşlev sembolü ve dosya bilgisi, " +"Heaptrack çalıştırıldığında hata ayıklama bilgisi eksik olduğunda bilinmiyor " +"olabilir." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" %2 içinde (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "tavan katkı: %1 (%​%2 toplam)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "sızan: %1 (%​%2 toplam)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "ayırmalar: %1 (%​%2 toplam)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "geçici: %1 (%​%2 ayırma, %​%3 toplam)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "geri iz:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "bir konumdan çağrıldı" +msgstr[1] "%1 konumdan çağrıldı" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %​%4/%3 toplam" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (öz): %2
  %​%4/%3 toplam" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (içeren): %2
  %​%4/%3 toplam" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "sembol: %1
ikili: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%2 içinde %1" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "<çözülmemiş işlev>" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" diff --git a/po/uk/heaptrack.po b/po/uk/heaptrack.po new file mode 100644 index 00000000..15bc0097 --- /dev/null +++ b/po/uk/heaptrack.po @@ -0,0 +1,1614 @@ +# Translation of heaptrack.po to Ukrainian +# Copyright (C) 2015-2020 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Yuri Chornoivan , 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2022-10-05 07:04+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 20.12.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Юрій Чорноіван" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "yurchor@ukr.net" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "Місце" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "Розміщення (власне)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "Тимчасове (власне)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "Пік (власне)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "Втрачено (власне)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "Розміщення (включене)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "Тимчасове (включене)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "Пік (включене)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "Втрачено (включене)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" +"Батьківський символ, яким було викликано функцію розподілу. Назва " +"функції може бути невідомою, якщо немає достатніх діагностичних даних." + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" +"Кількість викликів функції розподілу безпосередньо з цього місця." + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Кількість безпосередніх тимчасових розміщень у пам'яті. За цими " +"розміщеннями безпосередньо слідують вивільнення без інших проміжних " +"розміщень." + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"Максимальний об'єм резервної пам'яті, спожитої за викликами щодо " +"розміщення, що надходили безпосередньо з цього місця. Тут беруться до уваги " +"і скасування розподілу." + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" +"Байти розміщені безпосередньо за цією адресою, які не було вилучено із " +"розподіленої пам'яті." + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" +"Кількість включених викликів функції розподілу з цього місця або будь-" +"яких функцій, викликаних звідси." + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"Кількість включених тимчасових розміщень у пам'яті. За цими розміщеннями " +"безпосередньо слідують вивільнення без інших проміжних розміщень." + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"Включений максимальний об'єм резервної пам'яті, спожитої за викликами " +"щодо розміщення, що надходили з цього місця або від функцій, викликаних " +"звідси. Тут беруться до уваги і скасування розподілу." + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" +"Байти розміщені за цією адресою, які не було вилучено із розподіленої " +"пам'яті." + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "Зовнішній виклик" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "Внутрішній виклик" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "Пік" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "Втрачено" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "Розміщення" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "Тимчасове" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" +"Розташування %1. Назва функції може бути невідомою, якщо немає достатніх " +"діагностичних даних." + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" +"Місце у коді, з якого було викликано функцію розподілу. Може бути " +"невідомою, якщо немає достатніх діагностичних даних." + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "Розміщення у пам'яті" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "Спожита пам'ять" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "Тимчасові розміщення у пам'яті" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "Витрачений час" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "Загальне розміщення у пам'яті" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "Загальне споживання пам’яті" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "Загальні тимчасові розміщення у пам'яті" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 байтів)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "Загалом %1 розміщень за %2" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "Загалом %1 тимчасових розміщень за %2" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "Загалом спожито %1 за %2" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" +"%2 розміщення після %3 від:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" +"%2 тимчасових розміщення після %3 від:

%1" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 вжито після %3 від:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "Експортувати як…" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "Показ умовних позначень" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "Показати графік загальної вартості" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "Показати графік розподілу вартостей" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "Діаграми-стоси:" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "Фільтрувати за позначеним" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "Скинути фільтрування" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "Зберегти %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "растрове зображення (*.png *.jpg *.tiff);;векторне зображення (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "Не вдалося зберегти зображення до %1" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "ПочатокКінецьРізниця" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "Час%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "Спожито%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "Розміщення%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" +"Тимчасові розміщення%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"Показує зміну споживання пам'яті з купи з часом.
Натисніть кнопку " +"миші і перетягніть вказівник, щоб позначити діапазон часу для фільтрування." + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"Показує зміну кількості операцій із отримання пам'яті з часом." +"
Натисніть кнопку миші і перетягніть вказівник, щоб позначити діапазон " +"часу для фільтрування.
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"Показує зміну кількості операцій тимчасових розміщень у пам'яті з часом. " +"Тимчасовими вважаються розміщення, за якими безпосередньо слідують " +"вивільнення без інших проміжних розміщень.
Натисніть кнопку миші і " +"перетягніть вказівник, щоб позначити діапазон часу для фільтрування.
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1 (фільтровано з %2 до %3, Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1 (фільтрована різниця)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" +"Натисніть кнопку миші і перетягніть вказівник, щоб позначити діапазон часу " +"для фільтрування." + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" +"T= %1, спожито %2. Натисніть кнопку миші і перетягніть вказівник, щоб " +"позначити діапазон часу для фільтрування." + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" +"T= %1, розподілів %2. Натисніть кнопку миші і перетягніть вказівник, щоб " +"позначити діапазон часу для фільтрування." + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" +"T= %1, тимчасових розподілів %2. Натисніть кнопку миші і перетягніть " +"вказівник, щоб позначити діапазон часу для фільтрування." + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 розміщень у пам'яті загалом" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "Загалом тимчасових розміщень — %1" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "Пікове споживання пам'яті %1" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "Загалом витоки — %1" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) розміщень у пам'яті у %3 і нижче." + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) тимчасових розміщено у %3 і нижче." + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%1 (%2%) внесок до пікового споживання у %3 і нижче." + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) витоків у %3 і нижче." + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "Пік пам'яті" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" +"Показати графік внесків до пікового споживання пам'яті з купи у вашій " +"програмі." + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"Показати графік витоків пам'яті з купи у вашій програмі. Витоком вважається " +"таке отримання пам'яті, яке не завершується її поверненням до купи " +"розподілу. " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" +"Показати графік кількості операцій із отримання областей пам'яті, які " +"здійснюються функціями з вашого коду." + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"Показати графік кількості операцій із тимчасового отримання областей " +"пам'яті, які здійснюються функціями з вашого коду. Отримання областей " +"пам'яті вважаються тимчасовими, якщо за отриманням негайно слідує " +"скасовування такого отримання." + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "Виберіть джерело даних, які має бути показано на графіку." + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "Перегляд внизу вгору" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" +"Увімкнути показ графіка у режимі «внизу-вгору». Якщо пункт не буде " +"позначено, графік буде намальовано у режимі «згори-вниз»." + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "Згортати рекурсію" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" +"Згортати кадри стека для рекурсивних викликів функцій. Якщо цей пункт не " +"буде позначено, рекурсивні кадри візуалізуватимуться окремо." + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "Поріг вартості: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"Порогове значення вартості визначає максимальне відносне значення, яке " +"слід враховувати. Записи із відносною вартістю, що є нижчою за вказану, не " +"буде показано на графіку. Існування такого порогового значення передбачено " +"для оптимізації швидкості побудови графіків для великих наборів даних із " +"багатьма незначними записами. Якщо вам потрібна детальніша картина, зменшіть " +"значення цього параметра або встановіть для нього нульове значення." + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "Шукати…" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "Шукати на графіку символ." + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "Оновити перегляд" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "Переглянути зовнішні/внутрішні виклики" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "створюємо графік-полум'я…" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" +"%1 (%2% із загальної кількості у %3) отримань пам'яті відповідають критеріям " +"пошуку." + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "%1 (%2% із загальної кількості у %3) відповідають критеріям пошуку." + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Графічний інтерфейс Heaptrack" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Засіб візуалізації даних із файлів heaptrack." + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "© Milian Wolff , 2015" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "Автор початкової версії, супровідник" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "Базові дані профілювання, з якими слід порівнювати інші файли." + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" +"Список придушень витоків із вказаного файла. Придушення слід вказувати по " +"одному на рядок і починати кожен з рядків зі слова «leak:», тобто " +"використовувати формат файлів придушень LSAN." + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" +"Ігнорувати визначення придушень, які вбудовано до файла даних heaptrack. " +"Типово, heaptrack скопіює придушення, які додатково визначено за допомогою " +"символу «const char *__lsan_default_suppressions()» у програмі, яку " +"діагностують. Ці символи далі завжди буде застосовано при аналізі даних, " +"якщо відповідну можливість не буде явним чином вимкнено за допомогою цього " +"параметра командного рядка." + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" +"Ігнорувати визначення придушень, які вбудовано до heaptrack. Типово, " +"heaptrack придушуватиме певні відомі витоки у загальних бібліотеках системи." + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "Файли для завантаження" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[ФАЙЛ...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" +"%1 розміщень з %2, загалом розміщено %3 із середнім значенням %4 на одне " +"розміщення" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "Запитаний об'єм пам'яті" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "Кількість розміщень" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "Відкрити файл у редакторі" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
об'єкт діагностики:
%1 " +"(долучено)
" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
об'єкт діагностики:
%1
" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" +"
загальний час виконання:
%1, фільтровано з %2 до %3 (%4)" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "
загальний час виконання:
%1
" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
загалом пам'яті системи:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
виклики функцій розміщення:
%1 (%2/c)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
тимчасові розміщення у пам'яті:
%1 (%2%, %3/c)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
пікове споживання резервної пам'яті:
%1 за %2
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" +"
пікове RSS (разом із додатковими витратами heaptrack):
" +"%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
різниця у споживанні пам'яті:
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
загалом втрачено пам'яті:
%1 (%2 придушено)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
загалом втрачено пам'яті:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "Не вдалося обробити файл %1." + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "Спожито" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "Розміри" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "Вхідних даних %1 не існує." + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "Вхідні дані %1 не є файлом." + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "Вхідні дані %1 непридатні до читання." + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "Не вдалося обробити файл придушення." + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "Вимкнути вбудовані придушення" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "Вимкнути вбудовані придушення" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" +"Ігнорувати визначення придушень, які вбудовано до heaptrack. Типово, " +"heaptrack придушуватиме певні відомі витоки у загальних бібліотеках системи." + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "Завантажуємо файл %1, будь ласка, зачекайте…" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack — %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack — порівняння %1 з %2" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "Повторно обробляємо файл, будь ласка, зачекайте…" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "Навігація кодом" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "Нетипова…" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "Автоматична (без номерів рядків)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "Нетипова навігація кодом" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"Вкажіть команду, яку слід використовувати для навігації кодом. «%f» буде " +"замінено на назву файла, «%l» — номер рядка, а «%c» — на номер позиції у " +"рядку." + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "Головне вікно" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" +"Шлях до файла, у якому містяться правила придушення витоків у форматі LSAN." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "Відкриття даних heaptrack" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" +"

Вміст цього поля визначає основний файл даних heaptrack. Такі файли " +"даних мають назви heaptrack.$APP.$PID.gz або heaptrack.$APP." +"$PID.zst. Ви можете створити такий файл за допомогою профілювання вашої " +"програми, наприклад так:

\n" +"
heaptrack <ваша_програма> ...
\n" +"

Крім того, ви можете приєднатися до запущеного процесу командою

\n" +"
heaptrack --pid $(pidof <ваша_програма>)
" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "шлях/до/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"Крім того, ви можете вказати інший файл даних heaptrack для порівняння. " +"Якщо вибрано цей варіант, цей другий файл буде використано як базу: його " +"значення буде віднято від значень у основному файлі даних." + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "&Дані профілювання:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "Порівняти з:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "Придушення:" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "шлях/до/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "Резюме" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" +"Список функцій, яким дісталося найбільше пам'яті у вказаний момент часу." + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "Пікові внески" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "Список функцій, у яких сталися найбільші витоки пам'яті." + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "Найбільші витоки пам'яті" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "Список функцій, які отримували пам'ять найчастіше." + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "Найбільші розміщення у пам'яті" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" +"Список функцій, які створювали більшу частину тимчасових розміщень даних у " +"пам'яті." + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "Найбільші тимчасові розміщення у пам'яті" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "Придушення" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "Знизу-вгору" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "фільтрувати за функцією…" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "фільтрувати за файлом…" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "фільтрувати за модулем…" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "Відправник/Отримувач" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "Згори вниз" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "Графік-полум'я" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "С&теки" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "Вибраний стек:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "&Файл" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "П&араметри" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "Фільтр" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "об'єднуємо розміщення у пам'яті… %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "загалом" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "від 0 Б до 8 Б" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "від 9 Б до 16 Б" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "від 17 Б до 32 Б" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "від 33 Б до 64 Б" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "від 65 Б до 128 Б" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "від 129 Б до 256 Б" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "від 257 Б до 512 Б" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "від 512 Б до 1 кБ" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "понад 1 кБ" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "повторна обробка даних" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "обробка даних" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 прохід: %2 з %3 витрачено: %4 лишилося: %5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "об'єднуємо розміщення у пам'яті…" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "будуємо гістограму розмірів…" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "будуємо діаграми…" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "Зворотне трасування" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "Кількість викликів функції розподілу з цього місця." + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"Кількість тимчасових розміщень у пам'яті. За цими розміщеннями " +"безпосередньо слідують вивільнення без інших проміжних розміщень." + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" +"Внески із заданого місця до максимального споживання резервної пам'яті у " +"байтах. Тут беруться до уваги і скасування розподілу." + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"Місце, з якого було викликано функцію розподілу. Символ функції і дані " +"щодо файла можуть бути невідомими, якщо під час запуску heaptrack не було " +"знайдено достатніх діагностичних даних." + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" +"%1\n" +" у %2 (%3)" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "піковий внесок: %1 (%2% із загального)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "витоки: %1 (%2% від загального)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "розміщення: %1 (%2% від загального)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "тимчасово: %1 (%2% з розміщень, %3% з загального)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "зворотне трасування:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "викликано з %1 місця" +msgstr[1] "викликано з %1 місць" +msgstr[2] "викликано з %1 місць" +msgstr[3] "викликано з одного місця" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "%1: %2
  %4% з %3 загалом" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "%1 (лише сам): %2
  %4% з %3 загалом" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "%1 (із включенням): %2
  %4% з %3 загалом" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "символ: %1
двійковий: %2 (%3)" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "%1 у %2" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "<невизначена функція>" + +#~ msgid "heaptrack.*.*.gz heaptrack.*.*.zst" +#~ msgstr "heaptrack.*.*.gz heaptrack.*.*.zst" + +#~ msgid "KDevelop" +#~ msgstr "KDevelop" + +#~ msgid "Kate" +#~ msgstr "Kate" + +#~ msgid "KWrite" +#~ msgstr "KWrite" + +#~ msgid "gedit" +#~ msgstr "gedit" + +#~ msgid "gvim" +#~ msgstr "gvim" + +#~ msgid "Qt Creator" +#~ msgstr "Qt Creator" + +#~ msgid "%1 allocations from %2" +#~ msgstr "%1 розміщень з %2" + +#~ msgctxt "%1: function, %2: binary" +#~ msgid "%1 (%2)" +#~ msgstr "%1 (%2)" + +#~ msgid "%1 in %2 (%3)" +#~ msgstr "%1 у %2 (%3)" + +#~ msgid "Symbol" +#~ msgstr "Символ" + +#~ msgid "Binary" +#~ msgstr "Двійковий" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unresolved when debug information is missing." +#~ msgstr "" +#~ "Батьківська функція, якою було викликано функцію розподілу. Може бути " +#~ "невідомою, якщо немає достатніх діагностичних даних." + +#~ msgid "" +#~ "The module, i.e. executable or shared library, from which an " +#~ "allocation function was called." +#~ msgstr "" +#~ "Модуль, тобто виконуваний файл або бібліотека спільного використання, " +#~ "для якого було викликано функцію розподілу." + +#~ msgid "" +#~ "The function name of the %1. May be unresolved when debug information is " +#~ "missing." +#~ msgstr "" +#~ "Назва функції %1. Може бути невідомою, якщо немає достатніх діагностичних " +#~ "даних." + +#~ msgid "The name of the executable the symbol resides in." +#~ msgstr "Назва виконуваного файла, у якому перебуває символ." + +#~ msgid "Function" +#~ msgstr "Функція" + +#~ msgid "Module" +#~ msgstr "Модуль" + +#~ msgid "" +#~ "The parent function that called an allocation function. May be " +#~ "unknown when debug information is missing." +#~ msgstr "" +#~ "Батьківська функція, якою було викликано функцію розподілу. Може бути " +#~ "невідомою, якщо немає достатніх діагностичних даних." + +#~| msgctxt "1: function, 2: module" +#~| msgid "" +#~| "%1\n" +#~| " in %2" +#~ msgctxt "1: function, 2: module, 3: module path" +#~ msgid "" +#~ "%1\n" +#~ " in %2" +#~ msgstr "" +#~ "%1\n" +#~ " у %2" + +#~ msgid "File" +#~ msgstr "Файл" + +#~ msgid "Line" +#~ msgstr "Рядок" + +#~ msgid "Allocated (Self)" +#~ msgstr "Розміщено (власне)" + +#~ msgid "Allocated (Incl.)" +#~ msgstr "Розміщено (включене)" + +#~ msgid "" +#~ "The file where the allocation function was called from. May be empty " +#~ "when debug information is missing." +#~ msgstr "" +#~ "Файл, звідки було викликано функцію розподілу. Може мати порожнє " +#~ "значення, якщо немає достатніх діагностичних даних." + +#~ msgid "" +#~ "The line number where the allocation function was called from. May be " +#~ "empty when debug information is missing." +#~ msgstr "" +#~ "Номер рядка коду, звідки було викликано функцію розподілу. Може мати " +#~ "порожнє значення, якщо немає достатніх діагностичних даних." + +#~ msgid "" +#~ "The sum of all bytes directly allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Сума усіх байтів, безпосередньо розподілених з цього місця, без " +#~ "скасувань розподілу." + +#~ msgid "" +#~ "The inclusive sum of all bytes allocated from this location or " +#~ "functions called from here, ignoring deallocations." +#~ msgstr "" +#~ "Включена сума усіх байтів, розподілених з цього місця або функцій, " +#~ "викликаних звідси, без скасувань розподілу." + +#~ msgctxt "1: function, 2: file, 3: line, 4: module" +#~ msgid "" +#~ "%1\n" +#~ " at %2:%3\n" +#~ " in %4" +#~ msgstr "" +#~ "%1\n" +#~ " у %2:%3\n" +#~ " у %4" + +#~ msgid "" +#~ "inclusive: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at " +#~ "%5, leaked %6" +#~ msgstr "" +#~ "включене: розміщено %1 за %2 викликами (%3 тимчасово, тобто %4%), пік у " +#~ "%5, втрачено %6" + +#~ msgid "" +#~ "self: allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, " +#~ "leaked %6" +#~ msgstr "" +#~ "власне: розміщено %1 за %2 викликами (%3 тимчасово, тобто %4%), пік у %5, " +#~ "втрачено %6" + +#~ msgid "Memory Allocated" +#~ msgstr "Розподілена пам’ять" + +#~ msgid "%1 allocated in total after %2" +#~ msgstr "Загалом розміщено %1 після %2" + +#~ msgid "" +#~ "%2 allocated after %3 from:

%1

" +#~ msgstr "" +#~ "%2 розміщено після %3 від:

%1

" + +#~ msgid "" +#~ "Displays total memory allocated over time. This value ignores " +#~ "deallocations and just measures heap allocation throughput." +#~ msgstr "" +#~ "Показує зміну загального споживання розподіленої пам’яті з часом. " +#~ "Значення обчислено без враховування скасувань розподілу, це лише виміри " +#~ "отримання пам’яті з купи." + +#~ msgctxt "%1: allocated bytes, %2: relative number, %3: function label" +#~ msgid "%1 (%2%) allocated in %3 and below." +#~ msgstr "%1 (%2%) розміщено у %3 і нижче." + +#~ msgid "%1 contribution to peak consumption" +#~ msgstr "Внесок %1 до пікового споживання" + +#~ msgid "%1 allocated in total" +#~ msgstr "Загалом розміщено %1" + +#~ msgid "Allocated" +#~ msgstr "Розміщено" + +#~ msgid "" +#~ "Show a flame graph over the total memory allocated by functions in your " +#~ "code. This aggregates all memory allocations and ignores deallocations." +#~ msgstr "" +#~ "Показати графік загального отримання пам’яті функціями у вашому коді. " +#~ "Враховуються усі отримання пам’яті без врахування повернення пам’яті до " +#~ "купи." + +#~ msgid "%1 allocations from %2 at %3:%4 in %5" +#~ msgstr "%1 розміщень %2 у о %3:%4 у %5" + +#~ msgid "" +#~ "
bytes allocated in total (ignoring deallocations):
%1 " +#~ "(%2/s)
" +#~ msgstr "" +#~ "
загалом розподілено байтів (без повернення до резерву):
%1 (%2/с)
" + +#~ msgid "" +#~ "List of functions that allocated the most memory overall, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Список функцій, яким дісталося найбільше пам’яті загалом, без врахування " +#~ "скасування розміщення даних у пам’яті." + +#~ msgid "Most Memory Allocated" +#~ msgstr "Найбільші отримувачі пам’яті" + +#~ msgid "" +#~ "The sum of all bytes allocated from this location, ignoring " +#~ "deallocations." +#~ msgstr "" +#~ "Сума усіх байтів, розподілених з цього місця, без скасувань розподілу." +#~ "" + +#~ msgid "allocated: %1 (%2% of total)\n" +#~ msgstr "розміщено: %1 (%2% від загального)\n" + +#~ msgid "Open Heaptrack Output File" +#~ msgstr "Відкрити файл виведених результатів Heaptrack" + +#~ msgid "Heaptrack data files (heaptrack.*)" +#~ msgstr "файли даних Heaptrack (heaptrack.*)" + +#~ msgid "&Graphs" +#~ msgstr "&Графіки" + +#~ msgid "" +#~ "allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6" +#~ msgstr "" +#~ "розміщено %1 за %2 викликами (%3 тимчасово, тобто %4%), пік у %5, " +#~ "втрачено %6" + +#~ msgid "debuggee: %1" +#~ msgstr "debuggee: %1" + +#~ msgid "total runtime: %1s" +#~ msgstr "загальний час виконання: %1 с" + +#~ msgid "%1: %2 at %3" +#~ msgstr "%1: %2 за %3" + +#~ msgid "Allocations [-]" +#~ msgstr "Розміщення [-]" + +#~ msgid "Temporary Allocations [-]" +#~ msgstr "Тимчасові розміщення у пам’яті [-]" + +#~ msgid "Leaked [B]" +#~ msgstr "Втрачено [Б]" + +#~ msgid "Allocated [B]" +#~ msgstr "Розміщено [Б]" + +#~ msgid "time in ms" +#~ msgstr "час у мс" + +#~ msgid "memory heap size" +#~ msgstr "розмір динамічної пам’яті" diff --git a/po/zh_CN/heaptrack.po b/po/zh_CN/heaptrack.po new file mode 100644 index 00000000..dc6e4fa5 --- /dev/null +++ b/po/zh_CN/heaptrack.po @@ -0,0 +1,1255 @@ +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2023-10-21 13:54\n" +"Last-Translator: \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Project-ID: 269464\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf5-trunk/messages/heaptrack/heaptrack.pot\n" +"X-Crowdin-File-ID: 5826\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "KDE 中国" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde-china@kde.org" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "位置" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "分配 (Self)" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "临时(Self)" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "峰值 (Self)" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "泄漏(Self)" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "分配(内存)" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "临时(内存)" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "峰值(内存)" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "泄漏(内存)" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "从此位置直接调用分配函数的次数。" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"直接临时分配的数量。这些分配之后是免费分配,中间没有任何其他分配。。" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" +"直接源自此位置的分配消耗的最大堆内存(以字节为单位)。这考虑了处置。" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "直接分配到这个位置的字节尚未被分配。" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "包含从此位置调用分配函数或从此处调用的任何函数的次数。" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" +"包含临时分配的数量。这些分配之后是免费分配,中间没有任何其他分配。" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" +"源自此位置的分配或从此处调用的函数消耗的最大堆内存(以字节为单位)。这考" +"虑了处置。" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "分配给这个位置的字节尚未分配。" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "调用方" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "被调用方" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "峰值" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "泄漏" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "内存申请" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "临时" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "调用分配函数的源代码位置。当缺少调试信息时其可能是未知的。" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "内存申请" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "内存已使用" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "临时分配" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "已用时间" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "合计内存分配" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "合计内存消耗" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "合计临时分配" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "%1" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "%1 (%2 字节)" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "%1 分配总在 %2之后" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "%1 临时分配次数总计在 %2之后" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "%1 在 %2之后总消耗" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "%2 在 %3 之后分配:

%1

" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "%2 临时分配后 %3 来自:

%1

" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "%2 在 %3 之后消费:

%1

" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "导出为..." + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "显示图例" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "重置过滤器" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "保存 %1" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "栅格图像(*.png *.jpg *.tiff);矢量图形 (*.svg)" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "保存图像到 %1 失败" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "开始结束差值" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "时间%1%2%3" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "消耗%1%2%3" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "分配%1%2%3" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "临时分配%1%2%3" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" +"显示一段时间内的堆内存消耗。
点击并拖动以选择一个时间范围进行过滤。" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" +"显示随时间变化的内存分配数。
点击并拖拽以选择要筛选的时间范围。
" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" +"显示随时间变化的临时内存分配数。临时分配是指相应内存分配后紧接着被释放," +"中间没有发生其他分配。
点击并拖拽以选择要筛选的时间范围。
" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "%1(筛选自 %2 到 %3,Δ%4)" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "%1(筛选的差值)" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "点击并拖动以选择要筛选的时间范围。" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "T = %1,已消耗:%2。点击并拖动以选择要筛选的时间范围。" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "T = %1,已分配:%2。点击并拖动以选择要筛选的时间范围。" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "T = %1,临时分配:%2。点击并拖动以选择要筛选的时间范围。" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "%1 分配总计" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "%1 临时分配总计" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "%1 内存消耗峰值" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "%1 泄露总量" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "%1 (%2%) 在 %3 及以下的分配。" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "%1 (%2%) 在 %3 及以下的临时分配。" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "%3 及以下共对峰值资源消耗贡献了 %1 (%2%)。" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "%1 (%2%) 泄漏在 %3 及以下地方。" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "内存占用峰值" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "显示一个火焰图,描绘了您的程序对于峰值堆内存占用的贡献" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" +"在您的应用程序所泄露的堆内存上显示火焰图。从未被释放的内存被认为已泄露。 " + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "在您的代码中显示由函数触发的分配数的火焰图。" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" +"显示代码中函数触发的临时分配数的火焰图。当分配紧随其后的是解除分配时,它们被" +"标记为临时分配。" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "选择在火焰图形中可视化的数据源。" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "从下至上视图" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "启用自下而上的火焰图视图。如果不勾选,默认启用自上而下的视图。" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "折叠递归" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "折叠调用自身的函数的堆栈帧。如果未选中此选项,将单独可视化递归帧。" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "成本阈值: " + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" +"成本阈值定义分数截止值。相对成本低于此值的项目将不会显示在火焰图中。这样" +"做是为了优化,以便为内存开销低的大型数据集快速生成图形。如果需要更多详细信" +"息,请减小阈值或将其设置为零。" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "搜索..." + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "在火焰图中搜索符号。" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "重置视图" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "查看调用方/被调用方" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "正在生成火焰图..." + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "搜索共匹配了 %1 个 (共 %3 个中的 %2% 个) 分配。" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "搜索匹配了 %1 (共 %3 中的 %2%)。" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "Heaptrack 图形界面" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "Heaptrack 数据文件的可视化工具。" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "Copyright 2015, Milian Wolff " + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "Milian Wolff" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "原作者,维护者" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "比较其他文件的基本配置数据。" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "要加载的文件" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "[文件...]" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "请求的分配大小" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "分配数量" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "在编辑器中打开文件" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" +"
调试器:
%1 (附件)" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" +"
调试器:
%1
(附件" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "
系统内存总额:
%1
" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "
调用分配函数:
%1 (%2/s)
" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "
临时分配:
%1 (%2%, %3/s)
" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "
内存消耗峰值
%2 后 %1
" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "
峰RSS (包括Heaptrack 间接费用):
%1
" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "
内存消耗差值
%1
" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "
总体内存泄漏:
%1 (已排除 %2)
" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "
整个内存泄漏:
%1
" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "解析文件 %1 失败。" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "已消耗的" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "大小" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "输入数据 %1 不存在。" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "输入数据 %1 不是一个文件。" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "输入数据 %1 不可读。" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "Heaptrack" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "加载文件 %1,请稍候..." + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "Heaptrack - %1" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "Heaptrack - %1 与 %2 比较" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "正在重新解析文件,请稍候…" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr " / %1" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "代码导航" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "自定义..." + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "自动(无行号)" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "自定义代码导航" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" +"指定用于代码导航的命令,'%f' 会被替换成文件名,'%l' 会被替换成行号,'%c' 会被" +"替换成列号。" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "主窗口" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "包含 LSAN 格式的泄漏抑制规则的文件的路径。" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "打开Heaptrack 数据" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "path/to/heaptrack.$APP.$PID.{gz,zst}" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" +"您可以选择指定要与之比较的第二个heaptrack数据文件。如果设置,此文件将用作" +"基础文件,其成本将从主数据成本中减去。" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "个人资料&数据:" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "与之比较:" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "path/to/lsan_suppressions.txt" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "总计" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "在给定的时间分配最多内存的函数的列表。" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "峰值贡献" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "泄漏内存最多的函数的列表。" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "最大内存泄漏" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "最经常分配内存的函数的列表。" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "最多内存分配" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "最临时的内存分配的函数的列表。" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "最临时的分配" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "自底向上" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "按函数过滤..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "按文件过滤..." + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "按模块过滤..." + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "调用方 / 被调用方" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "自上而下" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "火焰图" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "S&tacks" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "选定的堆栈:" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "文件(&F)" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "设置(&N)" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "筛选" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "合并分配... %1%" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "总共" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "0B 到 8B" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "9B 到 16B" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "17B 到 32B" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "33B 到 64B" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "65B 到 128B" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "129B 到 256B" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "257B 到 512B" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "512B 到 1KB" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "超过 1KB" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "正在重新解析数据" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "正在解析数据" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "%1 轮数:%2/%3 花费:%4 剩余:%5" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "合并分配..." + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "正在构建大小直方图......" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "正在构建图表..." + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "回溯跟踪" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "分配函数从这个位置调用的次数" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" +"临时分配的数量。这些分配的直接后面是免费的,中间没有任何其他分配。" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "指定位置对峰值堆内存占用的贡献,以字节计。这也计入内存释放。" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" +"调用函数的位置。 当运行Heaptrack 时缺少调试信息时,函数符号和文件信息可能" +"未知" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "峰值贡献: %1 (合计的 %2%)\n" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "泄漏: %1 (占总数的%2%)\n" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "分配: %1 (占总数的%2%)\n" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "临时: %1 (%2%分配, %3%)\n" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "回溯跟踪:" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "从 %1 个位置被调用" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "??" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/po/zh_TW/heaptrack.po b/po/zh_TW/heaptrack.po new file mode 100644 index 00000000..35759b36 --- /dev/null +++ b/po/zh_TW/heaptrack.po @@ -0,0 +1,1230 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: heaptrack\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-11-05 12:37+0000\n" +"PO-Revision-Date: 2016-09-22 20:30+0800\n" +"Last-Translator: Jeff Huang \n" +"Language-Team: Traditional Chinese \n" +"Language: Traditional Chinese\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Translate Toolkit 1.10.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" + +#: gui/callercalleemodel.cpp:40 gui/callercalleemodel.h:333 +#: gui/treemodel.cpp:73 +#, kde-format +msgid "Location" +msgstr "" + +#: gui/callercalleemodel.cpp:42 gui/callercalleemodel.h:335 +#, kde-format +msgid "Allocations (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:44 gui/callercalleemodel.h:337 +#, kde-format +msgid "Temporary (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:46 gui/callercalleemodel.h:339 +#, kde-format +msgid "Peak (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:48 gui/callercalleemodel.h:341 +#, kde-format +msgid "Leaked (Self)" +msgstr "" + +#: gui/callercalleemodel.cpp:50 gui/callercalleemodel.h:343 +#, kde-format +msgid "Allocations (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:52 gui/callercalleemodel.h:345 +#, kde-format +msgid "Temporary (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:54 gui/callercalleemodel.h:347 +#, kde-format +msgid "Peak (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:56 gui/callercalleemodel.h:349 +#, kde-format +msgid "Leaked (Incl.)" +msgstr "" + +#: gui/callercalleemodel.cpp:63 +#, kde-format +msgid "" +"The parent symbol that called an allocation function. The function name " +"may be unresolved when debug information is missing." +msgstr "" + +#: gui/callercalleemodel.cpp:66 gui/callercalleemodel.h:359 +#, kde-format +msgid "" +"The number of times an allocation function was directly called from this " +"location." +msgstr "" + +#: gui/callercalleemodel.cpp:69 gui/callercalleemodel.h:362 +#, kde-format +msgid "" +"The number of direct temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:73 gui/callercalleemodel.h:366 +#, kde-format +msgid "" +"The maximum heap memory in bytes consumed from allocations originating " +"directly at this location. This takes deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:78 gui/callercalleemodel.h:371 +#, kde-format +msgid "" +"The bytes allocated directly at this location that have not been " +"deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:81 gui/callercalleemodel.h:181 +#: gui/callercalleemodel.h:374 +#, kde-format +msgid "" +"The inclusive number of times an allocation function was called from " +"this location or any functions called from here." +msgstr "" + +#: gui/callercalleemodel.cpp:85 gui/callercalleemodel.h:185 +#: gui/callercalleemodel.h:378 +#, kde-format +msgid "" +"The number of inclusive temporary allocations. These allocations are " +"directly followed by a free without any other allocations in-between." +msgstr "" + +#: gui/callercalleemodel.cpp:89 gui/callercalleemodel.h:173 +#: gui/callercalleemodel.h:382 +#, kde-format +msgid "" +"The inclusive maximum heap memory in bytes consumed from allocations " +"originating at this location or from functions called from here. This takes " +"deallocations into account." +msgstr "" + +#: gui/callercalleemodel.cpp:94 gui/callercalleemodel.h:178 +#: gui/callercalleemodel.h:387 gui/treemodel.cpp:91 +#, kde-format +msgid "" +"The bytes allocated at this location that have not been deallocated." +msgstr "" + +#: gui/callercalleemodel.cpp:202 +#, kde-format +msgid "Caller" +msgstr "" + +#: gui/callercalleemodel.cpp:214 +#, kde-format +msgid "Callee" +msgstr "" + +#: gui/callercalleemodel.h:156 gui/treemodel.cpp:69 gui/util.cpp:112 +#: gui/util.cpp:141 gui/util.cpp:170 +#, kde-format +msgid "Peak" +msgstr "" + +#: gui/callercalleemodel.h:158 gui/flamegraph.cpp:433 gui/treemodel.cpp:71 +#: gui/util.cpp:113 gui/util.cpp:142 gui/util.cpp:171 +#, kde-format +msgid "Leaked" +msgstr "" + +#: gui/callercalleemodel.h:160 gui/flamegraph.cpp:438 gui/mainwindow.cpp:477 +#: gui/treemodel.cpp:65 gui/util.cpp:114 gui/util.cpp:143 gui/util.cpp:172 +#, kde-format +msgid "Allocations" +msgstr "" + +#: gui/callercalleemodel.h:162 gui/treemodel.cpp:67 +#, kde-format +msgid "Temporary" +msgstr "" + +#: gui/callercalleemodel.h:170 +#, kde-format +msgid "" +"The location of the %1. The function name may be unresolved when debug " +"information is missing." +msgstr "" + +#: gui/callercalleemodel.h:356 +#, kde-format +msgid "" +"The source code location that called an allocation function. May be " +"unknown when debug information is missing." +msgstr "" + +#: gui/chartmodel.cpp:52 +#, kde-format +msgid "Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:54 +#, kde-format +msgid "Memory Consumed" +msgstr "" + +#: gui/chartmodel.cpp:56 gui/flamegraph.cpp:443 gui/mainwindow.cpp:479 +#: gui/util.cpp:115 gui/util.cpp:144 gui/util.cpp:173 +#, kde-format +msgid "Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:76 gui/chartwidget.cpp:466 +#, kde-format +msgid "Elapsed Time" +msgstr "" + +#: gui/chartmodel.cpp:83 +#, kde-format +msgid "Total Memory Allocations" +msgstr "" + +#: gui/chartmodel.cpp:85 +#, kde-format +msgid "Total Memory Consumption" +msgstr "" + +#: gui/chartmodel.cpp:87 +#, kde-format +msgid "Total Temporary Allocations" +msgstr "" + +#: gui/chartmodel.cpp:113 +#, kde-format +msgid "%1" +msgstr "" + +#: gui/chartmodel.cpp:166 +#, kde-format +msgctxt "" +"%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. " +"\"1300\"" +msgid "%1 (%2 bytes)" +msgstr "" + +#: gui/chartmodel.cpp:174 +#, kde-format +msgid "%1 allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:176 +#, kde-format +msgid "%1 temporary allocations in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:178 +#, kde-format +msgid "%1 consumed in total after %2" +msgstr "" + +#: gui/chartmodel.cpp:184 +#, kde-format +msgid "" +"%2 allocations after %3 from:

%1

" +msgstr "" + +#: gui/chartmodel.cpp:188 +#, kde-format +msgid "" +"%2 temporary allocations after %3 from:

%1" +msgstr "" + +#: gui/chartmodel.cpp:192 +#, kde-format +msgid "%2 consumed after %3 from:

%1

" +msgstr "" + +#: gui/chartwidget.cpp:162 +#, kde-format +msgid "Export As..." +msgstr "" + +#: gui/chartwidget.cpp:165 +#, kde-format +msgid "Show legend" +msgstr "" + +#: gui/chartwidget.cpp:172 +#, kde-format +msgid "Show total cost graph" +msgstr "" + +#: gui/chartwidget.cpp:180 +#, kde-format +msgid "Show detailed cost graph" +msgstr "" + +#: gui/chartwidget.cpp:187 +#, kde-format +msgid "Stacked diagrams:" +msgstr "" + +#: gui/chartwidget.cpp:234 +#, kde-format +msgid "Filter In On Selection" +msgstr "" + +#. i18n: ectx: property (text), widget (QMenu, menuFilter) +#: gui/chartwidget.cpp:244 gui/mainwindow.ui:891 +#, kde-format +msgid "Reset Filter" +msgstr "" + +#: gui/chartwidget.cpp:383 +#, kde-format +msgid "Save %1" +msgstr "" + +#: gui/chartwidget.cpp:384 +#, kde-format +msgid "Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)" +msgstr "" + +#: gui/chartwidget.cpp:400 +#, kde-format +msgid "Failed to save the image to %1" +msgstr "" + +#: gui/chartwidget.cpp:420 +#, kde-format +msgid "StartEndDelta" +msgstr "" + +#: gui/chartwidget.cpp:421 +#, kde-format +msgid "Time%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:425 +#, kde-format +msgid "Consumed%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:429 +#, kde-format +msgid "Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:433 +#, kde-format +msgid "" +"Temporary Allocations%1%2%3" +msgstr "" + +#: gui/chartwidget.cpp:441 +#, kde-format +msgid "" +"Shows the heap memory consumption over time.
Click and drag to select " +"a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:445 +#, kde-format +msgid "" +"Shows number of memory allocations over time.
Click and drag to " +"select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:449 +#, kde-format +msgid "" +"Shows number of temporary memory allocations over time. A temporary " +"allocation is one that is followed immediately by its corresponding " +"deallocation, without other allocations happening in-between.
Click and " +"drag to select a time range for filtering.
" +msgstr "" + +#: gui/chartwidget.cpp:471 +#, kde-format +msgid "%1 (filtered from %2 to %3, Δ%4)" +msgstr "" + +#: gui/chartwidget.cpp:475 +#, kde-format +msgid "%1 (filtered delta)" +msgstr "" + +#: gui/chartwidget.cpp:564 +#, kde-format +msgid "Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:570 +#, kde-format +msgid "" +"T = %1, Consumed: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:574 +#, kde-format +msgid "" +"T = %1, Allocations: %2. Click and drag to select time range for filtering." +msgstr "" + +#: gui/chartwidget.cpp:578 +#, kde-format +msgid "" +"T = %1, Temporary Allocations: %2. Click and drag to select time range for " +"filtering." +msgstr "" + +#: gui/flamegraph.cpp:175 gui/histogrammodel.cpp:63 +#, kde-format +msgid "%1 allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:177 +#, kde-format +msgid "%1 temporary allocations in total" +msgstr "" + +#: gui/flamegraph.cpp:179 +#, kde-format +msgid "%1 peak memory consumption" +msgstr "" + +#: gui/flamegraph.cpp:181 +#, kde-format +msgid "%1 leaked in total" +msgstr "" + +#: gui/flamegraph.cpp:234 +#, kde-format +msgctxt "%1: number of allocations, %2: relative number, %3: function label" +msgid "%1 (%2%) allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:239 +#, kde-format +msgctxt "" +"%1: number of temporary allocations, %2: relative number, %3 function label" +msgid "%1 (%2%) temporary allocations in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:244 +#, kde-format +msgctxt "" +"%1: peak consumption in bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) contribution to peak consumption in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:248 +#, kde-format +msgctxt "%1: leaked bytes, %2: relative number, %3: function label" +msgid "%1 (%2%) leaked in %3 and below." +msgstr "" + +#: gui/flamegraph.cpp:428 +#, kde-format +msgid "Memory Peak" +msgstr "" + +#: gui/flamegraph.cpp:430 +#, kde-format +msgid "" +"Show a flame graph over the contributions to the peak heap memory " +"consumption of your application." +msgstr "" + +#: gui/flamegraph.cpp:435 +#, kde-format +msgid "" +"Show a flame graph over the leaked heap memory of your application. Memory " +"is considered to be leaked when it never got deallocated. " +msgstr "" + +#: gui/flamegraph.cpp:440 +#, kde-format +msgid "" +"Show a flame graph over the number of allocations triggered by functions in " +"your code." +msgstr "" + +#: gui/flamegraph.cpp:445 +#, kde-format +msgid "" +"Show a flame graph over the number of temporary allocations triggered by " +"functions in your code. Allocations are marked as temporary when they are " +"immediately followed by their deallocation." +msgstr "" + +#: gui/flamegraph.cpp:452 +#, kde-format +msgid "Select the data source that should be visualized in the flame graph." +msgstr "" + +#: gui/flamegraph.cpp:467 +#, kde-format +msgid "Bottom-Up View" +msgstr "" + +#: gui/flamegraph.cpp:468 +#, kde-format +msgid "" +"Enable the bottom-up flame graph view. When this is unchecked, the top-down " +"view is enabled by default." +msgstr "" + +#: gui/flamegraph.cpp:476 +#, kde-format +msgid "Collapse Recursion" +msgstr "" + +#: gui/flamegraph.cpp:478 +#, kde-format +msgid "" +"Collapse stack frames for functions calling themselves. When this is " +"unchecked, recursive frames will be visualized separately." +msgstr "" + +#: gui/flamegraph.cpp:490 +#, kde-format +msgid "Cost Threshold: " +msgstr "" + +#: gui/flamegraph.cpp:494 +#, kde-format +msgid "" +"The cost threshold defines a fractional cut-off value. Items with a " +"relative cost below this value will not be shown in the flame graph. This is " +"done as an optimization to quickly generate graphs for large data sets with " +"low memory overhead. If you need more details, decrease the threshold value, " +"or set it to zero." +msgstr "" + +#: gui/flamegraph.cpp:506 +#, kde-format +msgid "Search..." +msgstr "" + +#: gui/flamegraph.cpp:507 +#, kde-format +msgid "Search the flame graph for a symbol." +msgstr "" + +#: gui/flamegraph.cpp:545 +#, kde-format +msgid "Reset View" +msgstr "" + +#: gui/flamegraph.cpp:555 gui/mainwindow.cpp:142 +#, kde-format +msgid "View Caller/Callee" +msgstr "" + +#: gui/flamegraph.cpp:696 +#, kde-format +msgid "generating flame graph..." +msgstr "" + +#: gui/flamegraph.cpp:773 +#, kde-format +msgid "%1 (%2% of total of %3) allocations matched by search." +msgstr "" + +#: gui/flamegraph.cpp:778 +#, kde-format +msgid "%1 (%2% of total of %3) matched by search." +msgstr "" + +#: gui/gui.cpp:67 +#, kde-format +msgid "Heaptrack GUI" +msgstr "" + +#: gui/gui.cpp:68 +#, kde-format +msgid "A visualizer for heaptrack data files." +msgstr "" + +#: gui/gui.cpp:69 +#, kde-format +msgid "Copyright 2015, Milian Wolff " +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Milian Wolff" +msgstr "" + +#: gui/gui.cpp:72 +#, kde-format +msgid "Original author, maintainer" +msgstr "" + +#: gui/gui.cpp:86 +#, kde-format +msgid "Base profile data to compare other files to." +msgstr "" + +#: gui/gui.cpp:91 +#, kde-format +msgid "" +"Load list of leak suppressions from the specified file. Specify one " +"suppression per line, and start each line with 'leak:', i.e. use the LSAN " +"suppression file format." +msgstr "" + +#: gui/gui.cpp:97 gui/mainwindow.cpp:642 +#, kde-format +msgid "" +"Ignore suppression definitions that are embedded into the heaptrack data " +"file. By default, heaptrack will copy the suppressions optionally defined " +"via a `const char *__lsan_default_suppressions()` symbol in the debuggee " +"application. These are then always applied when analyzing the data, unless " +"this feature is explicitly disabled using this command line option." +msgstr "" + +#: gui/gui.cpp:105 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks in common system libraries." +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "Files to load" +msgstr "" + +#: gui/gui.cpp:108 +#, kde-format +msgid "[FILE...]" +msgstr "" + +#: gui/histogrammodel.cpp:65 +#, kde-format +msgid "" +"%1 allocations from %2, totalling %3 allocated with an average of %4 per " +"allocation" +msgstr "" + +#: gui/histogramwidget.cpp:99 +#, kde-format +msgid "Requested Allocation Size" +msgstr "" + +#: gui/histogramwidget.cpp:105 +#, kde-format +msgid "Number of Allocations" +msgstr "" + +#: gui/mainwindow.cpp:171 +#, kde-format +msgid "Open file in editor" +msgstr "" + +#: gui/mainwindow.cpp:394 +#, kde-format +msgid "" +"
debuggee:
%1 " +"(attached)
" +msgstr "" + +#: gui/mainwindow.cpp:397 +#, kde-format +msgid "
debuggee:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:401 +#, kde-format +msgid "
total runtime:
%1, filtered from %2 to %3 (%4)
" +msgstr "" + +#: gui/mainwindow.cpp:406 +#, kde-format +msgid "
total runtime:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:408 +#, kde-format +msgid "
total system memory:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:415 +#, kde-format +msgid "
calls to allocation functions:
%1 (%2/s)
" +msgstr "" + +#: gui/mainwindow.cpp:418 +#, kde-format +msgid "
temporary allocations:
%1 (%2%, %3/s)
" +msgstr "" + +#: gui/mainwindow.cpp:428 +#, kde-format +msgid "
peak heap memory consumption:
%1 after %2
" +msgstr "" + +#: gui/mainwindow.cpp:431 +#, kde-format +msgid "
peak RSS (including heaptrack overhead):
%1
" +msgstr "" + +#: gui/mainwindow.cpp:435 +#, kde-format +msgid "
memory consumption delta:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:439 +#, kde-format +msgid "
total memory leaked:
%1 (%2 suppressed)
" +msgstr "" + +#: gui/mainwindow.cpp:442 +#, kde-format +msgid "
total memory leaked:
%1
" +msgstr "" + +#: gui/mainwindow.cpp:470 +#, kde-format +msgid "Failed to parse file %1." +msgstr "" + +#: gui/mainwindow.cpp:475 +#, kde-format +msgid "Consumed" +msgstr "" + +#: gui/mainwindow.cpp:491 +#, kde-format +msgid "Sizes" +msgstr "" + +#: gui/mainwindow.cpp:555 +#, kde-format +msgid "Input data %1 does not exist." +msgstr "" + +#: gui/mainwindow.cpp:557 +#, kde-format +msgid "Input data %1 is not a file." +msgstr "" + +#: gui/mainwindow.cpp:559 +#, kde-format +msgid "Input data %1 is not readable." +msgstr "" + +#: gui/mainwindow.cpp:597 +#, kde-format +msgid "Failed to parse suppression file." +msgstr "" + +#: gui/mainwindow.cpp:612 +#, kde-format +msgid "Heaptrack" +msgstr "" + +#: gui/mainwindow.cpp:640 +#, kde-format +msgid "Disable Embedded Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:652 +#, kde-format +msgid "Disable Builtin Suppressions" +msgstr "" + +#: gui/mainwindow.cpp:654 +#, kde-format +msgid "" +"Ignore suppression definitions that are built into heaptrack. By default, " +"heaptrack will suppress certain known leaks from common system libraries." +msgstr "" + +#: gui/mainwindow.cpp:682 +#, kde-format +msgid "Loading file %1, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:684 +#, kde-format +msgctxt "%1: file name that is open" +msgid "Heaptrack - %1" +msgstr "" + +#: gui/mainwindow.cpp:687 +#, kde-format +msgctxt "%1, %2: file names that are open" +msgid "Heaptrack - %1 compared to %2" +msgstr "" + +#: gui/mainwindow.cpp:703 +#, kde-format +msgid "Reparsing file, please wait..." +msgstr "" + +#: gui/mainwindow.cpp:746 +#, kde-format +msgid " / %1" +msgstr "" + +#: gui/mainwindow.cpp:786 +#, kde-format +msgid "Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:813 +#, kde-format +msgid "Custom..." +msgstr "" + +#: gui/mainwindow.cpp:825 +#, kde-format +msgid "Automatic (No Line numbers)" +msgstr "" + +#: gui/mainwindow.cpp:845 +#, kde-format +msgid "Custom Code Navigation" +msgstr "" + +#: gui/mainwindow.cpp:846 +#, kde-format +msgid "" +"Specify command to use for code navigation, '%f' will be replaced by the " +"file name, '%l' by the line number and '%c' by the column number." +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QMainWindow, MainWindow) +#: gui/mainwindow.ui:14 +#, kde-format +msgid "MainWindow" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QMainWindow, MainWindow) +#. i18n: ectx: property (toolTip), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:17 gui/mainwindow.ui:118 +#, kde-format +msgid "Path to a file containing leak suppression rules in the LSAN format." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox) +#: gui/mainwindow.ui:63 +#, kde-format +msgid "Open Heaptrack Data" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, openFile) +#: gui/mainwindow.ui:72 +#, kde-format +msgid "" +"

This field specifies the primary heaptrack data file. These files are " +"called heaptrack.$APP.$PID.gz or heaptrack.$APP.$PID.zst. " +"You can produce such a file by profiling your application, e.g. via:

\n" +"
heaptrack <yourapplication> ...
\n" +"

Or, alternatively, you can attach to a running process via

\n" +"
heaptrack --pid $(pidof <yourapplication>)
" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, openFile) +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:75 gui/mainwindow.ui:88 +#, kde-format +msgid "path/to/heaptrack.$APP.$PID.{gz,zst}" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (KUrlRequester, compareTo) +#: gui/mainwindow.ui:85 +#, kde-format +msgid "" +"You can optionally specify a second heaptrack data file to compare to. " +"If set, this file will be used as a base and its cost gets subtracted from " +"the primary data costs." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, openFileLabel) +#: gui/mainwindow.ui:98 +#, kde-format +msgid "Profile &Data:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, compareToLabel) +#: gui/mainwindow.ui:108 +#, kde-format +msgid "Compare to:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, suppressionsLabel) +#: gui/mainwindow.ui:121 +#, kde-format +msgid "Suppressions:" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (KUrlRequester, suppressions) +#: gui/mainwindow.ui:131 +#, kde-format +msgid "path/to/lsan_suppressions.txt" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, summaryTab) +#: gui/mainwindow.ui:244 +#, kde-format +msgid "Summary" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topPeakLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topPeak) +#: gui/mainwindow.ui:345 gui/mainwindow.ui:358 +#, kde-format +msgid "List of functions that allocated the most memory at a given time." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topPeakLabel) +#: gui/mainwindow.ui:348 +#, kde-format +msgid "Peak Contributions" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topLeakedLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topLeaked) +#: gui/mainwindow.ui:384 gui/mainwindow.ui:397 +#, kde-format +msgid "List of functions that leak the most memory." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topLeakedLabel) +#: gui/mainwindow.ui:387 +#, kde-format +msgid "Largest Memory Leaks" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topAllocationsLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topAllocations) +#: gui/mainwindow.ui:423 gui/mainwindow.ui:436 +#, kde-format +msgid "List of functions that allocate memory most often." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topAllocationsLabel) +#: gui/mainwindow.ui:426 +#, kde-format +msgid "Most Memory Allocations" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QLabel, topTemporaryLabel) +#. i18n: ectx: property (toolTip), widget (QTreeView, topTemporary) +#: gui/mainwindow.ui:465 gui/mainwindow.ui:478 +#, kde-format +msgid "List of functions that produced the most temporary memory allocations." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, topTemporaryLabel) +#: gui/mainwindow.ui:468 +#, kde-format +msgid "Most Temporary Allocations" +msgstr "" + +#. i18n: ectx: property (title), widget (KCollapsibleGroupBox, suppressionBox) +#: gui/mainwindow.ui:501 +#, kde-format +msgid "Suppressions" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, bottomUpTab) +#: gui/mainwindow.ui:533 +#, kde-format +msgid "Bottom-Up" +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterFunction) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFunction) +#: gui/mainwindow.ui:557 gui/mainwindow.ui:625 gui/mainwindow.ui:746 +#, kde-format +msgid "filter by function..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterFile) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterFile) +#: gui/mainwindow.ui:564 gui/mainwindow.ui:753 +#, kde-format +msgid "filter by file..." +msgstr "" + +#. i18n: ectx: property (placeholderText), widget (QLineEdit, bottomUpFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, callerCalleeFilterModule) +#. i18n: ectx: property (placeholderText), widget (QLineEdit, topDownFilterModule) +#: gui/mainwindow.ui:571 gui/mainwindow.ui:632 gui/mainwindow.ui:760 +#, kde-format +msgid "filter by module..." +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, callerCalleeTab) +#: gui/mainwindow.ui:601 +#, kde-format +msgid "Caller / Callee" +msgstr "" + +#. i18n: ectx: attribute (title), widget (QWidget, topDownTab) +#: gui/mainwindow.ui:725 +#, kde-format +msgid "Top-Down" +msgstr "" + +#. i18n: ectx: attribute (title), widget (FlameGraph, flameGraphTab) +#: gui/mainwindow.ui:790 +#, kde-format +msgid "Flame Graph" +msgstr "" + +#. i18n: ectx: property (windowTitle), widget (QDockWidget, stacksDock) +#: gui/mainwindow.ui:806 +#, kde-format +msgid "S&tacks" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, stackSpinnerLabel) +#: gui/mainwindow.ui:831 +#, kde-format +msgid "Selected Stack:" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_File) +#: gui/mainwindow.ui:868 +#, kde-format +msgid "&File" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menu_Settings) +#: gui/mainwindow.ui:873 +#, kde-format +msgid "Setti&ngs" +msgstr "" + +#. i18n: ectx: property (title), widget (QMenu, menuFilter) +#: gui/mainwindow.ui:878 +#, kde-format +msgid "Filter" +msgstr "" + +#: gui/parser.cpp:387 +#, kde-format +msgid "merging allocations... %1%" +msgstr "" + +#: gui/parser.cpp:557 +#, kde-format +msgid "total" +msgstr "" + +#: gui/parser.cpp:559 +#, kde-format +msgid "0B to 8B" +msgstr "" + +#: gui/parser.cpp:560 +#, kde-format +msgid "9B to 16B" +msgstr "" + +#: gui/parser.cpp:561 +#, kde-format +msgid "17B to 32B" +msgstr "" + +#: gui/parser.cpp:562 +#, kde-format +msgid "33B to 64B" +msgstr "" + +#: gui/parser.cpp:563 +#, kde-format +msgid "65B to 128B" +msgstr "" + +#: gui/parser.cpp:564 +#, kde-format +msgid "129B to 256B" +msgstr "" + +#: gui/parser.cpp:565 +#, kde-format +msgid "257B to 512B" +msgstr "" + +#: gui/parser.cpp:566 +#, kde-format +msgid "512B to 1KB" +msgstr "" + +#: gui/parser.cpp:567 +#, kde-format +msgid "more than 1KB" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "reparsing data" +msgstr "" + +#: gui/parser.cpp:645 +#, kde-format +msgid "parsing data" +msgstr "" + +#: gui/parser.cpp:659 +#, kde-format +msgid "%1 pass: %2/%3 spent: %4 remaining: %5" +msgstr "" + +#: gui/parser.cpp:715 +#, kde-format +msgid "merging allocations..." +msgstr "" + +#: gui/parser.cpp:726 +#, kde-format +msgid "building size histogram..." +msgstr "" + +#: gui/parser.cpp:739 +#, kde-format +msgid "building charts..." +msgstr "" + +#: gui/stacksmodel.cpp:99 +#, kde-format +msgid "Backtrace" +msgstr "" + +#: gui/treemodel.cpp:80 +#, kde-format +msgid "" +"The number of times an allocation function was called from this location." +"" +msgstr "" + +#: gui/treemodel.cpp:83 +#, kde-format +msgid "" +"The number of temporary allocations. These allocations are directly " +"followed by a free without any other allocations in-between." +msgstr "" + +#: gui/treemodel.cpp:87 +#, kde-format +msgid "" +"The contributions from a given location to the maximum heap memory " +"consumption in bytes. This takes deallocations into account." +msgstr "" + +#: gui/treemodel.cpp:94 +#, kde-format +msgid "" +"The location from which an allocation function was called. Function " +"symbol and file information may be unknown when debug information was " +"missing when heaptrack was run." +msgstr "" + +#: gui/treemodel.cpp:149 gui/treemodel.cpp:173 +#, kde-format +msgctxt "1: function, 2: module, 3: module path" +msgid "" +"%1\n" +" in %2 (%3)" +msgstr "" + +#: gui/treemodel.cpp:159 +#, kde-format +msgid "peak contribution: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:160 +#, kde-format +msgid "leaked: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:161 +#, kde-format +msgid "allocations: %1 (%2% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:162 +#, kde-format +msgid "temporary: %1 (%2% of allocations, %3% of total)\n" +msgstr "" + +#: gui/treemodel.cpp:168 +#, kde-format +msgid "backtrace:" +msgstr "" + +#: gui/treemodel.cpp:180 +#, kde-format +msgid "called from one location" +msgid_plural "called from %1 locations" +msgstr[0] "" + +#: gui/util.cpp:32 +#, kde-format +msgid "??" +msgstr "" + +#: gui/util.cpp:108 +#, kde-format +msgid "%1: %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:134 gui/util.cpp:163 +#, kde-format +msgid "%1 (self): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:137 gui/util.cpp:166 +#, kde-format +msgid "%1 (inclusive): %2
  %4% out of %3 total" +msgstr "" + +#: gui/util.cpp:183 +#, kde-format +msgid "symbol: %1
binary: %2 (%3)" +msgstr "" + +#: gui/util.cpp:187 +#, kde-format +msgctxt "%1: function name, %2: binary basename" +msgid "%1 in %2" +msgstr "" + +#: gui/util.cpp:209 +#, kde-format +msgid "" +msgstr "" diff --git a/src/analyze/CMakeLists.txt b/src/analyze/CMakeLists.txt index 46c04ce2..c3cc7884 100644 --- a/src/analyze/CMakeLists.txt +++ b/src/analyze/CMakeLists.txt @@ -2,7 +2,7 @@ if (ECM_FOUND) include(ECMEnableSanitizers) endif() -find_package(Boost 1.41.0 REQUIRED COMPONENTS iostreams program_options) +find_package(Boost 1.41.0 REQUIRED COMPONENTS iostreams program_options system filesystem) configure_file(analyze_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/analyze_config.h) @@ -15,14 +15,17 @@ include_directories( add_library(sharedprint STATIC accumulatedtracedata.cpp + suppressions.cpp ) -target_link_libraries(sharedprint LINK_PUBLIC - ${Boost_LIBRARIES} - ${ZLIB_LIBRARIES} +target_link_libraries(sharedprint + PUBLIC + ${Boost_LIBRARIES} + ${ZLIB_LIBRARIES} + tsl::robin_map ) -if (ZSTD_FOUND) +if (ZSTD_FOUND AND NOT BOOST_IOSTREAMS_HAS_ZSTD) target_link_libraries(sharedprint LINK_PUBLIC boost-zstd ) @@ -31,16 +34,23 @@ endif() add_subdirectory(print) if(HEAPTRACK_BUILD_GUI) - find_package(Qt5 5.10.0 NO_MODULE OPTIONAL_COMPONENTS Widgets) - find_package(ECM 1.0.0 NO_MODULE) - if(Qt5_FOUND AND ECM_FOUND) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) - find_package(KF5 COMPONENTS CoreAddons I18n ItemModels ThreadWeaver ConfigWidgets KIO) - find_package(KChart "2.6.0") + find_package(Qt${QT_VERSION_MAJOR} ${QT_MIN_VERSION} ${REQUIRED_IN_APPIMAGE} NO_MODULE OPTIONAL_COMPONENTS Widgets) + set_package_properties(Qt${QT_VERSION_MAJOR} PROPERTIES TYPE RECOMMENDED PURPOSE "Required for the heaptrack_gui executable.") + find_package(ECM 1.0.0 ${REQUIRED_IN_APPIMAGE} NO_MODULE) + set_package_properties(ECM PROPERTIES TYPE RECOMMENDED PURPOSE "KDE's extra-cmake-modules, required for the heaptrack_gui executable.") + if(Qt${QT_VERSION_MAJOR}_FOUND AND ECM_FOUND) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + find_package(KF${QT_VERSION_MAJOR} ${REQUIRED_IN_APPIMAGE} COMPONENTS CoreAddons I18n ItemModels ThreadWeaver ConfigWidgets KIO IconThemes) + find_package(KChart ${REQUIRED_IN_APPIMAGE} "2.6.0") set_package_properties(KChart PROPERTIES TYPE RECOMMENDED PURPOSE "Required for the heaptrack_gui executable. Get it from the kdiagram module.") + if(KF${QT_VERSION_MAJOR}I18n_FOUND) + ki18n_install(../../po) + endif() + else() + message(WARNING "Required Qt/KF dependencies for building heaptrack GUI not found") endif() endif() -if (KF5_FOUND) +if (KF${QT_VERSION_MAJOR}_FOUND) add_subdirectory(gui) endif() diff --git a/src/analyze/accumulatedtracedata.cpp b/src/analyze/accumulatedtracedata.cpp index a805e543..38fb8fd1 100644 --- a/src/analyze/accumulatedtracedata.cpp +++ b/src/analyze/accumulatedtracedata.cpp @@ -1,44 +1,36 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "accumulatedtracedata.h" +#include "analyze_config.h" #include #include #include #include -#include #include #include +#if ZSTD_FOUND +#if BOOST_IOSTREAMS_HAS_ZSTD +#include +#else +#include +#endif +#endif #include +#include + #include "util/config.h" #include "util/linereader.h" +#include "util/macroutils.h" #include "util/pointermap.h" -#include "analyze_config.h" - -#ifdef __GNUC__ -#define POTENTIALLY_UNUSED __attribute__((unused)) -#else -#define POTENTIALLY_UNUSED -#endif +#include "suppressions.h" using namespace std; @@ -56,6 +48,32 @@ ostream& operator<<(ostream& out, const Index index) out << index.index; return out; } + +// boost's counter filter uses an int for the count which overflows for large streams; so replace it with a work alike. +class byte_counter +{ +public: + using char_type = char; + using category = boost::iostreams::multichar_input_filter_tag; + + uint64_t bytes() const + { + return m_bytes; + } + + template + std::streamsize read(Source& src, char* str, std::streamsize size) + { + auto const readsize = boost::iostreams::read(src, str, size); + if (readsize == -1) + return -1; + m_bytes += readsize; + return readsize; + } + +private: + uint64_t m_bytes = 0; +}; } AccumulatedTraceData::AccumulatedTraceData() @@ -69,6 +87,8 @@ AccumulatedTraceData::AccumulatedTraceData() opNewIpIndices.reserve(16); } +AccumulatedTraceData::~AccumulatedTraceData() = default; + const string& AccumulatedTraceData::stringify(const StringIndex stringId) const { if (!stringId || stringId.index > strings.size()) { @@ -121,16 +141,12 @@ string AccumulatedTraceData::prettyFunction(const string& function) const return ret; } -bool AccumulatedTraceData::read(const string& inputFile) +bool AccumulatedTraceData::read(const string& inputFile, bool isReparsing) { - if (totalTime == 0) { - return read(inputFile, FirstPass) && read(inputFile, SecondPass); - } else { - return read(inputFile, ThirdPass); - } + return read(inputFile, FirstPass, isReparsing) && read(inputFile, SecondPass, isReparsing); } -bool AccumulatedTraceData::read(const string& inputFile, const ParsePass pass) +bool AccumulatedTraceData::read(const string& inputFile, const ParsePass pass, bool isReparsing) { const bool isGzCompressed = boost::algorithm::ends_with(inputFile, ".gz"); const bool isZstdCompressed = boost::algorithm::ends_with(inputFile, ".zst"); @@ -143,6 +159,7 @@ bool AccumulatedTraceData::read(const string& inputFile, const ParsePass pass) } boost::iostreams::filtering_istream in; + in.push(byte_counter()); // caution, ::read dependant on filter order if (isGzCompressed) { in.push(boost::iostreams::gzip_decompressor()); } else if (isZstdCompressed) { @@ -153,12 +170,15 @@ bool AccumulatedTraceData::read(const string& inputFile, const ParsePass pass) return false; #endif } + in.push(byte_counter()); // caution, ::read dependant on filter order in.push(file); - return read(in, pass); + parsingState.fileSize = boost::filesystem::file_size(inputFile); + + return read(in, pass, isReparsing); } -bool AccumulatedTraceData::read(istream& in, const ParsePass pass) +bool AccumulatedTraceData::read(boost::iostreams::filtering_istream& in, const ParsePass pass, bool isReparsing) { LineReader reader; int64_t timeStamp = 0; @@ -181,13 +201,24 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) totalCost = {}; peakTime = 0; - systemInfo = {}; + if (pass == FirstPass) { + if (!filterParameters.disableBuiltinSuppressions) { + suppressions = builtinSuppressions(); + } + + suppressions.resize(suppressions.size() + filterParameters.suppressions.size()); + std::transform(filterParameters.suppressions.begin(), filterParameters.suppressions.end(), suppressions.begin(), + [](const std::string& pattern) { + return Suppression {pattern, 0, 0}; + }); + } peakRSS = 0; for (auto& allocation : allocations) { allocation.clearCost(); } unsigned int fileVersion = 0; bool debuggeeEncountered = false; + bool inFilteredTime = !filterParameters.minTime; // required for backwards compatibility // newer versions handle this in heaptrack_interpret already @@ -198,12 +229,31 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) // allocations, i.e. when a deallocation follows with the same data uint64_t lastAllocationPtr = 0; - while (reader.getLine(in)) { + const auto uncompressedCount = in.component(0); + const auto compressedCount = in.component(in.size() - 2); + + parsingState.pass = pass; + parsingState.reparsing = isReparsing; + + while (timeStamp < filterParameters.maxTime && reader.getLine(in)) { + parsingState.readCompressedByte = compressedCount->bytes(); + parsingState.readUncompressedByte = uncompressedCount->bytes(); + parsingState.timestamp = timeStamp; + if (reader.mode() == 's') { - if (pass != FirstPass) { + if (pass != FirstPass || isReparsing) { continue; } - strings.push_back(reader.line().substr(2)); + if (fileVersion >= 3) { + // read sized string directly + std::string string; + reader >> string; + strings.push_back(std::move(string)); + } else { + // read remaining line as string, possibly including white spaces + strings.push_back(reader.line().substr(2)); + } + StringIndex index; index.index = strings.size(); @@ -219,7 +269,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) } } } else if (reader.mode() == 't') { - if (pass != FirstPass) { + if (pass != FirstPass || isReparsing) { continue; } TraceNode node; @@ -231,7 +281,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) } traces.push_back(node); } else if (reader.mode() == 'i') { - if (pass != FirstPass) { + if (pass != FirstPass || isReparsing) { continue; } InstructionPointer ip; @@ -254,11 +304,14 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) opNewIpIndices.push_back(index); } } else if (reader.mode() == '+') { + if (!inFilteredTime) { + continue; + } AllocationInfo info; AllocationInfoIndex allocationIndex; if (fileVersion >= 1) { if (!(reader >> allocationIndex)) { - cerr << "failed to parse line: " << reader.line() << endl; + cerr << "failed to parse line: " << reader.line() << ' ' << __LINE__ << endl; continue; } else if (allocationIndex.index >= allocationInfos.size()) { cerr << "allocation index out of bounds: " << allocationIndex @@ -271,7 +324,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) uint64_t ptr = 0; TraceIndex traceIndex; if (!(reader >> info.size) || !(reader >> traceIndex) || !(reader >> ptr)) { - cerr << "failed to parse line: " << reader.line() << endl; + cerr << "failed to parse line: " << reader.line() << ' ' << __LINE__ << endl; continue; } info.allocationIndex = mapToAllocationIndex(traceIndex); @@ -303,6 +356,9 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) } } } else if (reader.mode() == '-') { + if (!inFilteredTime) { + continue; + } AllocationInfoIndex allocationInfoIndex; bool temporary = false; if (fileVersion >= 1) { @@ -341,7 +397,7 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) } } } else if (reader.mode() == 'a') { - if (pass != FirstPass) { + if (pass != FirstPass || isReparsing) { continue; } AllocationInfo info; @@ -362,11 +418,15 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) cerr << "Failed to read time stamp: " << reader.line() << endl; continue; } - if (pass != FirstPass) { - handleTimeStamp(timeStamp, newStamp); + inFilteredTime = newStamp >= filterParameters.minTime && newStamp <= filterParameters.maxTime; + if (inFilteredTime) { + handleTimeStamp(timeStamp, newStamp, false, pass); } timeStamp = newStamp; } else if (reader.mode() == 'R') { // RSS timestamp + if (!inFilteredTime) { + continue; + } int64_t rss = 0; reader >> rss; if (rss > peakRSS) { @@ -378,10 +438,12 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) return false; } debuggeeEncountered = true; - if (pass != FirstPass) { + if (pass != FirstPass && !isReparsing) { handleDebuggee(reader.line().c_str() + 2); } } else if (reader.mode() == 'A') { + if (pass != FirstPass || isReparsing) + continue; totalCost = {}; fromAttached = true; } else if (reader.mode() == 'v') { @@ -402,20 +464,32 @@ bool AccumulatedTraceData::read(istream& in, const ParsePass pass) << endl; return false; } + if (fileVersion >= 3) { + reader.setExpectedSizedStrings(true); + } } else if (reader.mode() == 'I') { // system information reader >> systemInfo.pageSize; reader >> systemInfo.pages; + } else if (reader.mode() == 'S') { // embedded suppression + if (pass != FirstPass || filterParameters.disableEmbeddedSuppressions) { + continue; + } + auto suppression = parseSuppression(reader.line().substr(2)); + if (!suppression.empty()) { + suppressions.push_back({std::move(suppression), 0, 0}); + } } else { cerr << "failed to parse line: " << reader.line() << endl; } } - if (pass == FirstPass) { + if (pass == FirstPass && !isReparsing) { totalTime = timeStamp + 1; - } else { - handleTimeStamp(timeStamp, totalTime); + filterParameters.maxTime = totalTime; } + handleTimeStamp(timeStamp, timeStamp + 1, true, pass); + return true; } @@ -435,7 +509,9 @@ vector sortedIndices(size_t numIndices, SortF sorter) vector remapStrings(vector& lhs, const vector& rhs) { - unordered_map stringRemapping; + tsl::robin_map stringRemapping; + + // insert known strings in lhs into the map for lookup below StringIndex stringIndex; { stringRemapping.reserve(lhs.size()); @@ -445,6 +521,9 @@ vector remapStrings(vector& lhs, const vector& rhs) } } + // now insert the missing strings form rhs into lhs + // and create a remapped string vector, keeping the order + // of the strings in rhs, but mapping into the string vector from lhs vector map; { map.reserve(rhs.size() + 1); @@ -452,6 +531,8 @@ vector remapStrings(vector& lhs, const vector& rhs) for (const auto& string : rhs) { auto it = stringRemapping.find(string); if (it == stringRemapping.end()) { + // a string that only occurs in rhs, but not lhs + // add it to lhs to make sure we can find it again later on ++stringIndex.index; lhs.push_back(string); map.push_back(stringIndex); @@ -463,11 +544,21 @@ vector remapStrings(vector& lhs, const vector& rhs) return map; } -template -inline T identity(const T& t) +// replace by std::identity once we can leverage C++20 +struct identity { - return t; -} + template + const T& operator()(const T& t) const + { + return t; + } + + template + T operator()(T&& t) const + { + return std::move(t); + } +}; template int compareTraceIndices(const TraceIndex& lhs, const AccumulatedTraceData& lhsData, const TraceIndex& rhs, @@ -501,6 +592,11 @@ int compareTraceIndices(const TraceIndex& lhs, const AccumulatedTraceData& lhsDa return lhsIp.compareWithoutAddress(rhsIp) ? -1 : 1; } +POTENTIALLY_UNUSED void printCost(const AllocationData& data) +{ + cerr << data.allocations << " (" << data.temporary << "), " << data.peak << " (" << data.leaked << ")\n"; +} + POTENTIALLY_UNUSED void printTrace(const AccumulatedTraceData& data, TraceIndex index) { do { @@ -517,6 +613,23 @@ POTENTIALLY_UNUSED void printTrace(const AccumulatedTraceData& data, TraceIndex } while (index); cerr << "---\n"; } + +template +ForwardIt inplace_unique_reduce(ForwardIt first, ForwardIt last, BinaryPredicateCompare cmp, BinaryOpReduce reduce) +{ + if (first == last) + return last; + + ForwardIt result = first; + while (++first != last) { + if (cmp(*result, *first)) { + reduce(*result, *first); + } else if (++result != first) { + *result = std::move(*first); + } + } + return ++result; +} } void AccumulatedTraceData::diff(const AccumulatedTraceData& base) @@ -527,28 +640,22 @@ void AccumulatedTraceData::diff(const AccumulatedTraceData& base) systemInfo.pages -= base.systemInfo.pages; systemInfo.pageSize -= base.systemInfo.pageSize; - // step 1: sort trace indices of allocations for efficient lookup - // step 2: while at it, also merge equal allocations - vector allocationTraceNodes; - allocationTraceNodes.reserve(allocations.size()); - for (auto it = allocations.begin(); it != allocations.end();) { - const auto& allocation = *it; - auto sortedIt = - lower_bound(allocationTraceNodes.begin(), allocationTraceNodes.end(), allocation.traceIndex, - [this](const TraceIndex& lhs, const TraceIndex& rhs) -> bool { - return compareTraceIndices(lhs, *this, rhs, *this, identity) < 0; - }); - if (sortedIt == allocationTraceNodes.end() - || compareTraceIndices(allocation.traceIndex, *this, *sortedIt, *this, identity) != 0) { - allocationTraceNodes.insert(sortedIt, allocation.traceIndex); - ++it; - } else if (*sortedIt != allocation.traceIndex) { - findAllocation(*sortedIt) += allocation; - it = allocations.erase(it); - } else { - ++it; - } - } + // step 1: sort allocations for efficient lookup and to prepare for merging equal allocations + + std::sort(allocations.begin(), allocations.end(), [this](const Allocation& lhs, const Allocation& rhs) { + return compareTraceIndices(lhs.traceIndex, *this, rhs.traceIndex, *this, identity {}) < 0; + }); + + // step 2: now merge equal allocations + + allocations.erase(inplace_unique_reduce( + allocations.begin(), allocations.end(), + [this](const Allocation& lhs, const Allocation& rhs) { + return compareTraceIndices(lhs.traceIndex, *this, rhs.traceIndex, *this, identity {}) + == 0; + }, + [](Allocation& lhs, const Allocation& rhs) { lhs += rhs; }), + allocations.end()); // step 3: map string indices from rhs to lhs data @@ -629,33 +736,24 @@ void AccumulatedTraceData::diff(const AccumulatedTraceData& base) }; // find an equivalent trace or copy the data over if it does not exist yet - // a trace is equivalent if the complete backtrace has equal - // InstructionPointer + // a trace is equivalent if the complete backtrace has equal InstructionPointer // data while ignoring the actual pointer address - auto remapTrace = [&base, &allocationTraceNodes, this, remapIp, copyTrace](TraceIndex rhsIndex) -> TraceIndex { - if (!rhsIndex) { - return rhsIndex; - } + for (const auto& rhsAllocation : base.allocations) { - auto it = lower_bound(allocationTraceNodes.begin(), allocationTraceNodes.end(), rhsIndex, - [&base, this, remapIp](const TraceIndex& lhs, const TraceIndex& rhs) -> bool { - return compareTraceIndices(lhs, *this, rhs, base, remapIp) < 0; + assert(rhsAllocation.traceIndex); + auto it = lower_bound(allocations.begin(), allocations.end(), rhsAllocation.traceIndex, + [&base, this, remapIp](const Allocation& lhs, const TraceIndex& rhs) -> bool { + return compareTraceIndices(lhs.traceIndex, *this, rhs, base, remapIp) < 0; }); - if (it != allocationTraceNodes.end() && compareTraceIndices(*it, *this, rhsIndex, base, remapIp) == 0) { - return *it; + if (it == allocations.end() + || compareTraceIndices(it->traceIndex, *this, rhsAllocation.traceIndex, base, remapIp) != 0) { + Allocation lhsAllocation; + lhsAllocation.traceIndex = copyTrace(rhsAllocation.traceIndex); + it = allocations.insert(it, lhsAllocation); } - TraceIndex ret = copyTrace(rhsIndex); - allocationTraceNodes.insert(it, ret); - return ret; - }; - - for (const auto& rhsAllocation : base.allocations) { - const auto lhsTrace = remapTrace(rhsAllocation.traceIndex); - assert(remapIp(base.findIp(base.findTrace(rhsAllocation.traceIndex).ipIndex)) - .equalWithoutAddress(findIp(findTrace(lhsTrace).ipIndex))); - findAllocation(lhsTrace) -= rhsAllocation; + (*it) -= rhsAllocation; } // step 5: remove allocations that don't show any differences @@ -663,7 +761,7 @@ void AccumulatedTraceData::diff(const AccumulatedTraceData& base) // we can still end up with merged backtraces that have a total // of 0, but different "tails" of different origin with non-zero cost allocations.erase(remove_if(allocations.begin(), allocations.end(), - [](const Allocation& allocation) -> bool { return allocation == AllocationData(); }), + [&](const Allocation& allocation) -> bool { return allocation == AllocationData(); }), allocations.end()); } @@ -686,29 +784,26 @@ AllocationIndex AccumulatedTraceData::mapToAllocationIndex(const TraceIndex trac allocations.push_back(allocation); } else if (traceIndex == m_maxAllocationTraceIndex && !allocations.empty()) { // reuse the last allocation - assert(allocations.back().traceIndex == traceIndex); - allocationIndex.index = allocations.size() - 1; + assert(allocations[m_maxAllocationIndex.index].traceIndex == traceIndex); + allocationIndex = m_maxAllocationIndex; } else { // new allocation allocationIndex.index = allocations.size(); traceIndexToAllocationIndex.push_back(make_pair(traceIndex, allocationIndex)); Allocation allocation; allocation.traceIndex = traceIndex; + m_maxAllocationIndex.index = allocations.size(); allocations.push_back(allocation); m_maxAllocationTraceIndex = traceIndex; } return allocationIndex; } -Allocation& AccumulatedTraceData::findAllocation(const TraceIndex traceIndex) -{ - return allocations[mapToAllocationIndex(traceIndex).index]; -} - -InstructionPointer AccumulatedTraceData::findIp(const IpIndex ipIndex) const +const InstructionPointer& AccumulatedTraceData::findIp(const IpIndex ipIndex) const { + static const InstructionPointer invalid; if (!ipIndex || ipIndex.index > instructionPointers.size()) { - return {}; + return invalid; } else { return instructionPointers[ipIndex.index - 1]; } @@ -727,3 +822,122 @@ bool AccumulatedTraceData::isStopIndex(const StringIndex index) const { return find(stopIndices.begin(), stopIndices.end(), index) != stopIndices.end(); } + +struct SuppressionStringMatch +{ + static constexpr auto NO_MATCH = std::numeric_limits::max(); + + SuppressionStringMatch(std::size_t index = NO_MATCH) + : suppressionIndex(index) + { + } + + explicit operator bool() const + { + return suppressionIndex != NO_MATCH; + } + + std::size_t suppressionIndex; +}; + +void AccumulatedTraceData::applyLeakSuppressions() +{ + totalLeakedSuppressed = 0; + + if (suppressions.empty()) { + return; + } + + // match all strings once against all suppression rules + bool hasAnyMatch = false; + std::vector suppressedStrings(strings.size()); + std::transform(strings.begin(), strings.end(), suppressedStrings.begin(), [&](const auto& string) { + auto it = std::find_if(suppressions.begin(), suppressions.end(), [&string](const Suppression& suppression) { + return matchesSuppression(suppression.pattern, string); + }); + if (it == suppressions.end()) { + return SuppressionStringMatch(); + } else { + hasAnyMatch = true; + return SuppressionStringMatch(static_cast(std::distance(suppressions.begin(), it))); + } + }); + if (!hasAnyMatch) { + // nothing matched the suppressions, we can return early + return; + } + + auto isSuppressedString = [&suppressedStrings](StringIndex index) { + if (index && index.index <= suppressedStrings.size()) { + return suppressedStrings[index.index - 1]; + } else { + return SuppressionStringMatch(); + } + }; + auto isSuppressedFrame = [&isSuppressedString](Frame frame) { + auto match = isSuppressedString(frame.functionIndex); + if (match) { + return match; + } + return isSuppressedString(frame.fileIndex); + }; + + // now match all instruction pointers against the suppressed strings + std::vector suppressedIps(instructionPointers.size()); + std::transform(instructionPointers.begin(), instructionPointers.end(), suppressedIps.begin(), [&](const auto& ip) { + auto match = isSuppressedString(ip.moduleIndex); + if (match) { + return match; + } + match = isSuppressedFrame(ip.frame); + if (match) { + return match; + } + for (const auto& inlined : ip.inlined) { + match = isSuppressedFrame(inlined); + if (match) { + return match; + } + } + return SuppressionStringMatch(); + }); + suppressedStrings = {}; + auto isSuppressedIp = [&suppressedIps](IpIndex index) { + if (index && index.index <= suppressedIps.size()) { + return suppressedIps[index.index - 1]; + } + return SuppressionStringMatch(); + }; + + // now match all trace indices against the suppressed instruction pointers + std::vector suppressedTraces(traces.size()); + auto isSuppressedTrace = [&suppressedTraces](TraceIndex index) { + if (index && index.index <= suppressedTraces.size()) { + return suppressedTraces[index.index - 1]; + } + return SuppressionStringMatch(); + }; + std::transform(traces.begin(), traces.end(), suppressedTraces.begin(), [&](const auto& trace) { + auto match = isSuppressedTrace(trace.parentIndex); + if (match) { + return match; + } + return isSuppressedIp(trace.ipIndex); + }); + suppressedIps = {}; + + // now finally zero all the matching allocations + for (auto& allocation : allocations) { + auto match = isSuppressedTrace(allocation.traceIndex); + if (match) { + totalLeakedSuppressed += allocation.leaked; + + auto& suppression = suppressions[match.suppressionIndex]; + ++suppression.matches; + suppression.leaked += allocation.leaked; + + totalCost.leaked -= allocation.leaked; + allocation.leaked = 0; + } + } +} diff --git a/src/analyze/accumulatedtracedata.h b/src/analyze/accumulatedtracedata.h index d191710b..b45d4be5 100644 --- a/src/analyze/accumulatedtracedata.h +++ b/src/analyze/accumulatedtracedata.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef ACCUMULATEDTRACEDATA_H #define ACCUMULATEDTRACEDATA_H @@ -24,13 +12,11 @@ #include #include -#include -#include -#include -#include +#include #include "allocationdata.h" +#include "filterparameters.h" #include "util/indices.h" struct Frame @@ -41,9 +27,7 @@ struct Frame bool operator==(const Frame& rhs) const { - return functionIndex == rhs.functionIndex && - fileIndex == rhs.fileIndex && - line == rhs.line; + return functionIndex == rhs.functionIndex && fileIndex == rhs.fileIndex && line == rhs.line; } bool operator<(const Frame& rhs) const @@ -96,20 +80,13 @@ struct AllocationInfo } }; +struct Suppression; + struct AccumulatedTraceData { AccumulatedTraceData(); - virtual ~AccumulatedTraceData() = default; - - virtual void handleTimeStamp(int64_t oldStamp, int64_t newStamp) = 0; - virtual void handleAllocation(const AllocationInfo& info, const AllocationInfoIndex index) = 0; - virtual void handleDebuggee(const char* command) = 0; + virtual ~AccumulatedTraceData(); - const std::string& stringify(const StringIndex stringId) const; - - std::string prettyFunction(const std::string& function) const; - - bool read(const std::string& inputFile); enum ParsePass { // find time of total peak cost @@ -119,13 +96,24 @@ struct AccumulatedTraceData // GUI only: graph-building ThirdPass }; - bool read(const std::string& inputFile, const ParsePass pass); - bool read(std::istream& in, const ParsePass pass); + + virtual void handleTimeStamp(int64_t oldStamp, int64_t newStamp, bool isFinalTimeStamp, const ParsePass pass) = 0; + virtual void handleAllocation(const AllocationInfo& info, const AllocationInfoIndex index) = 0; + virtual void handleDebuggee(const char* command) = 0; + + const std::string& stringify(const StringIndex stringId) const; + + std::string prettyFunction(const std::string& function) const; + + bool read(const std::string& inputFile, bool isReparsing); + bool read(const std::string& inputFile, const ParsePass pass, bool isReparsing); + bool read(boost::iostreams::filtering_istream& in, const ParsePass pass, bool isReparsing); void diff(const AccumulatedTraceData& base); bool shortenTemplates = false; bool fromAttached = false; + FilterParameters filterParameters; std::vector allocations; AllocationData totalCost; @@ -142,8 +130,9 @@ struct AccumulatedTraceData // our indices are sequentially increasing thus a new allocation can only ever // occur with an index larger than any other we encountered so far - // this can be used to our advantage in speeding up the findAllocation calls. + // this can be used to our advantage in speeding up the mapToAllocationIndex calls. TraceIndex m_maxAllocationTraceIndex; + AllocationIndex m_maxAllocationIndex; // we don't want to shuffle allocations around, so instead keep a secondary // vector around for efficient index lookup std::vector> traceIndexToAllocationIndex; @@ -152,10 +141,8 @@ struct AccumulatedTraceData /// if the trace index wasn't mapped before, an empty Allocation will be added /// and its index returned. AllocationIndex mapToAllocationIndex(const TraceIndex traceIndex); - /// map the trace index to an allocation and return a reference to it - Allocation& findAllocation(const TraceIndex traceIndex); - InstructionPointer findIp(const IpIndex ipIndex) const; + const InstructionPointer& findIp(const IpIndex ipIndex) const; TraceNode findTrace(const TraceIndex traceIndex) const; @@ -170,6 +157,22 @@ struct AccumulatedTraceData std::vector opNewIpIndices; std::vector allocationInfos; + + struct ParsingState + { + int64_t fileSize = 0; // bytes + int64_t readCompressedByte = 0; + int64_t readUncompressedByte = 0; + int64_t timestamp = 0; // ms + ParsePass pass = ParsePass::FirstPass; + bool reparsing = false; + }; + + ParsingState parsingState; + + void applyLeakSuppressions(); + std::vector suppressions; + int64_t totalLeakedSuppressed = 0; }; #endif // ACCUMULATEDTRACEDATA_H diff --git a/src/analyze/allocationdata.h b/src/analyze/allocationdata.h index db1e0fc1..5b6e0d37 100644 --- a/src/analyze/allocationdata.h +++ b/src/analyze/allocationdata.h @@ -1,20 +1,8 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef ALLOCATIONDATA_H #define ALLOCATIONDATA_H diff --git a/src/analyze/analyze_config.h.cmake b/src/analyze/analyze_config.h.cmake index 15106147..f88385ea 100644 --- a/src/analyze/analyze_config.h.cmake +++ b/src/analyze/analyze_config.h.cmake @@ -1,24 +1,13 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef HEAPTRACK_ANALYZE_CONFIG_H #define HEAPTRACK_ANALYZE_CONFIG_H +#cmakedefine01 BOOST_IOSTREAMS_HAS_ZSTD #cmakedefine01 ZSTD_FOUND #endif // HEAPTRACK_ANALYZE_CONFIG_H diff --git a/src/analyze/filterparameters.h b/src/analyze/filterparameters.h new file mode 100644 index 00000000..c830beb3 --- /dev/null +++ b/src/analyze/filterparameters.h @@ -0,0 +1,28 @@ +/* + SPDX-FileCopyrightText: 2015-2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#ifndef FILTERPARAMETERS_H +#define FILTERPARAMETERS_H + +#include +#include +#include +#include + +struct FilterParameters +{ + int64_t minTime = 0; + int64_t maxTime = std::numeric_limits::max(); + std::vector suppressions; + bool disableEmbeddedSuppressions = false; + bool disableBuiltinSuppressions = false; + bool isFilteredByTime(int64_t totalTime) const + { + return minTime != 0 || maxTime < totalTime; + } +}; + +#endif // FILTERPARAMETERS_H diff --git a/src/analyze/gui/CMakeLists.txt b/src/analyze/gui/CMakeLists.txt index b152c05d..f5803b67 100644 --- a/src/analyze/gui/CMakeLists.txt +++ b/src/analyze/gui/CMakeLists.txt @@ -15,14 +15,11 @@ include(ECMAddTests) include(ECMInstallIcons) include(ECMAddAppIcon) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -option(APPIMAGE_BUILD "configure build for bundling in an appimage" OFF) - configure_file(gui_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/gui_config.h) -add_definitions(-Wall - -DQT_NO_URL_CAST_FROM_STRING +add_compile_options(-Wall) + +add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII -DQT_NO_CAST_FROM_BYTEARRAY -DQT_USE_QSTRINGBUILDER @@ -33,14 +30,26 @@ add_library(heaptrack_gui_private STATIC parser.cpp ) target_link_libraries(heaptrack_gui_private PUBLIC - KF5::I18n - KF5::CoreAddons # KFormat - KF5::ThreadWeaver - Qt5::Core + KF${QT_VERSION_MAJOR}::I18n + KF${QT_VERSION_MAJOR}::CoreAddons # KFormat + KF${QT_VERSION_MAJOR}::ThreadWeaver + Qt${QT_VERSION_MAJOR}::Core sharedprint pthread ${CMAKE_THREAD_LIBS_INIT} ) +if (BUILD_COVERAGE) + # FIXME: this should be handled within ECM instead of workarounded here + target_link_libraries(heaptrack_gui_private PRIVATE -lgcov) +endif() + +target_compile_definitions(heaptrack_gui_private PRIVATE TRANSLATION_DOMAIN="heaptrack") + +target_include_directories(heaptrack_gui_private PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../ + ${Boost_INCLUDE_DIRS} +) set(SRCFILES gui.cpp @@ -48,10 +57,13 @@ set(SRCFILES treemodel.cpp treeproxy.cpp costdelegate.cpp + costheaderview.cpp flamegraph.cpp stacksmodel.cpp topproxy.cpp callercalleemodel.cpp + proxystyle.cpp + suppressionsmodel.cpp resources.qrc ) @@ -61,11 +73,12 @@ ecm_add_app_icon(SRCFILES ICONS ) set(LIBRARIES - Qt5::Widgets - KF5::ItemModels - KF5::ConfigWidgets - KF5::I18n - KF5::KIOWidgets + Qt${QT_VERSION_MAJOR}::Widgets + KF${QT_VERSION_MAJOR}::ItemModels + KF${QT_VERSION_MAJOR}::ConfigWidgets + KF${QT_VERSION_MAJOR}::I18n + KF${QT_VERSION_MAJOR}::KIOWidgets + KF${QT_VERSION_MAJOR}::IconThemes sharedprint heaptrack_gui_private ) @@ -80,6 +93,7 @@ if (KChart_FOUND) ) list(APPEND LIBRARIES KChart + Qt${QT_VERSION_MAJOR}::Svg ) endif() @@ -93,15 +107,15 @@ target_link_libraries(heaptrack_gui ) install(TARGETS heaptrack_gui - ${INSTALL_TARGETS_DEFAULT_ARGS} + ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) set_target_properties(heaptrack_gui PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}" + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${KDE_INSTALL_BINDIR}" ) install(PROGRAMS org.kde.heaptrack.desktop - DESTINATION ${XDG_APPS_INSTALL_DIR} + DESTINATION ${KDE_INSTALL_APPDIR} ) install(FILES org.kde.heaptrack.appdata.xml diff --git a/src/analyze/gui/callercalleemodel.cpp b/src/analyze/gui/callercalleemodel.cpp index 78371bd0..30a66d2b 100644 --- a/src/analyze/gui/callercalleemodel.cpp +++ b/src/analyze/gui/callercalleemodel.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2016-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "callercalleemodel.h" @@ -30,6 +18,7 @@ CallerCalleeModel::~CallerCalleeModel() = default; void CallerCalleeModel::setResults(const CallerCalleeResults& results) { + Q_ASSERT(results.resultData); m_results = results; setRows(results.entries); } @@ -43,16 +32,12 @@ void CallerCalleeModel::clearData() QVariant CallerCalleeModel::headerCell(int column, int role) const { if (role == Qt::InitialSortOrderRole) { - return (column > BinaryColumn) ? Qt::DescendingOrder : Qt::AscendingOrder; + return (column > LocationColumn) ? Qt::DescendingOrder : Qt::AscendingOrder; } if (role == Qt::DisplayRole) { switch (static_cast(column)) { case LocationColumn: return i18n("Location"); - case SymbolColumn: - return i18n("Symbol"); - case BinaryColumn: - return i18n("Binary"); case SelfAllocationsColumn: return i18n("Allocations (Self)"); case SelfTemporaryColumn: @@ -77,12 +62,6 @@ QVariant CallerCalleeModel::headerCell(int column, int role) const case LocationColumn: return i18n("The parent symbol that called an allocation function. " "The function name may be unresolved when debug information is missing."); - case SymbolColumn: - return i18n("The parent function that called an allocation function. " - "May be unresolved when debug information is missing."); - case BinaryColumn: - return i18n("The module, i.e. executable or shared library, from " - "which an allocation function was called."); case SelfAllocationsColumn: return i18n("The number of times an allocation function was directly " "called from this location."); @@ -128,12 +107,7 @@ QVariant CallerCalleeModel::cell(int column, int role, const Symbol& symbol, con } else if (role == SortRole) { switch (static_cast(column)) { case LocationColumn: - // TODO: optimize this - return QString(symbol.symbol + symbol.binary); - case SymbolColumn: - return symbol.symbol; - case BinaryColumn: - return symbol.binary; + return Util::toString(symbol, *m_results.resultData, Util::Short); case SelfAllocationsColumn: // NOTE: we sort by unsigned absolute value return QVariant::fromValue(std::abs(entry.selfCost.allocations)); @@ -155,36 +129,28 @@ QVariant CallerCalleeModel::cell(int column, int role, const Symbol& symbol, con break; } } else if (role == TotalCostRole) { + const auto& totalCosts = m_results.resultData->totalCosts(); switch (static_cast(column)) { case SelfAllocationsColumn: case InclusiveAllocationsColumn: - return QVariant::fromValue(m_results.totalCosts.allocations); + return QVariant::fromValue(totalCosts.allocations); case SelfTemporaryColumn: case InclusiveTemporaryColumn: - return QVariant::fromValue(m_results.totalCosts.temporary); + return QVariant::fromValue(totalCosts.temporary); case SelfPeakColumn: case InclusivePeakColumn: - return QVariant::fromValue(m_results.totalCosts.peak); + return QVariant::fromValue(totalCosts.peak); case SelfLeakedColumn: case InclusiveLeakedColumn: - return QVariant::fromValue(m_results.totalCosts.leaked); + return QVariant::fromValue(totalCosts.leaked); case LocationColumn: - case SymbolColumn: - case BinaryColumn: case NUM_COLUMNS: break; } - } else if (role == FilterRole) { - // TODO: optimize this - return QString(symbol.symbol + symbol.binary); } else if (role == Qt::DisplayRole) { switch (static_cast(column)) { case LocationColumn: - return i18nc("%1: function name, %2: binary basename", "%1 in %2", symbol.symbol, symbol.binary); - case SymbolColumn: - return symbol.symbol; - case BinaryColumn: - return symbol.binary; + return Util::toString(symbol, *m_results.resultData, Util::Short); case SelfAllocationsColumn: return QVariant::fromValue(entry.selfCost.allocations); case SelfTemporaryColumn: @@ -211,9 +177,9 @@ QVariant CallerCalleeModel::cell(int column, int role, const Symbol& symbol, con } else if (role == SourceMapRole) { return QVariant::fromValue(entry.sourceMap); } else if (role == Qt::ToolTipRole) { - return Util::formatTooltip(symbol, entry.selfCost, entry.inclusiveCost, m_results.totalCosts); - } else if (role == TotalCostsRole) { - return QVariant::fromValue(m_results.totalCosts); + return Util::formatTooltip(symbol, entry.selfCost, entry.inclusiveCost, *m_results.resultData); + } else if (role == ResultDataRole) { + return QVariant::fromValue(m_results.resultData.get()); } return {}; @@ -259,3 +225,5 @@ int CallerCalleeModel::numColumns() const { return NUM_COLUMNS; } + +#include "moc_callercalleemodel.cpp" diff --git a/src/analyze/gui/callercalleemodel.h b/src/analyze/gui/callercalleemodel.h index ff5ff8d4..8b7432de 100644 --- a/src/analyze/gui/callercalleemodel.h +++ b/src/analyze/gui/callercalleemodel.h @@ -1,20 +1,8 @@ /* - * Copyright 2016-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef CALLERCALLEEMODEL_H #define CALLERCALLEEMODEL_H @@ -22,10 +10,12 @@ #include #include +#include + #include "../allocationdata.h" #include "hashmodel.h" #include "locationdata.h" -#include "summarydata.h" +#include "resultdata.h" #include "util.h" using SymbolCostMap = QHash; @@ -46,33 +36,6 @@ Q_DECLARE_METATYPE(LocationCostMap) struct CallerCalleeEntry : EntryCost { - EntryCost& source(const FileLine& location) - { - auto it = sourceMap.find(location); - if (it == sourceMap.end()) { - it = sourceMap.insert(location, {}); - } - return *it; - } - - AllocationData& callee(const Symbol& symbol) - { - auto it = callees.find(symbol); - if (it == callees.end()) { - it = callees.insert(symbol, {}); - } - return *it; - } - - AllocationData& caller(const Symbol& symbol) - { - auto it = callers.find(symbol); - if (it == callers.end()) { - it = callers.insert(symbol, {}); - } - return *it; - } - // callers, i.e. other symbols and locations that called this symbol CallerMap callers; // callees, i.e. symbols being called from this symbol @@ -85,17 +48,7 @@ using CallerCalleeEntryMap = QHash; struct CallerCalleeResults { CallerCalleeEntryMap entries; - - CallerCalleeEntry& entry(const Symbol& symbol) - { - auto it = entries.find(symbol); - if (it == entries.end()) { - it = entries.insert(symbol, {}); - } - return *it; - } - - AllocationData totalCosts; + std::shared_ptr resultData; }; Q_DECLARE_TYPEINFO(CallerCalleeResults, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(CallerCalleeResults) @@ -108,13 +61,15 @@ class CallerCalleeModel : public HashModel virtual ~SymbolCostModelImpl() = default; - void setResults(const SymbolCostMap& map, const AllocationData& totalCost) + void setResults(const SymbolCostMap& map, std::shared_ptr resultData) { - m_totalCosts = totalCost; + Q_ASSERT(resultData); + m_resultData = std::move(resultData); HashModel::setRows(map); } enum Columns { - SymbolColumn = 0, - BinaryColumn, - LocationColumn, + LocationColumn = 0, PeakColumn, LeakedColumn, AllocationsColumn, @@ -188,21 +141,17 @@ class SymbolCostModelImpl : public HashModel { SortRole = Qt::UserRole, TotalCostRole, - FilterRole, SymbolRole }; QVariant headerCell(int column, int role) const final override { - if (role == Qt::InitialSortOrderRole && column > BinaryColumn) { + if (role == Qt::InitialSortOrderRole && column != LocationColumn) { return Qt::DescendingOrder; } else if (role == Qt::DisplayRole) { switch (static_cast(column)) { case LocationColumn: - case SymbolColumn: return symbolHeader(); - case BinaryColumn: - return i18n("Binary"); case PeakColumn: return i18n("Peak"); case LeakedColumn: @@ -220,11 +169,6 @@ class SymbolCostModelImpl : public HashModel return i18n( "The location of the %1. The function name may be unresolved when debug information is missing.", symbolHeader()); - case SymbolColumn: - return i18n("The function name of the %1. May be unresolved when debug information is missing.", - symbolHeader()); - case BinaryColumn: - return i18n("The name of the executable the symbol resides in."); case PeakColumn: return i18n("The inclusive maximum heap memory in bytes consumed " "from allocations originating at this " @@ -254,10 +198,7 @@ class SymbolCostModelImpl : public HashModel if (role == SortRole) { switch (static_cast(column)) { case LocationColumn: - case SymbolColumn: - return symbol.symbol; - case BinaryColumn: - return symbol.binary; + return QVariant::fromValue(symbol); case PeakColumn: // NOTE: we sort by unsigned absolute value return QVariant::fromValue(std::abs(costs.peak)); @@ -281,22 +222,13 @@ class SymbolCostModelImpl : public HashModel case TemporaryColumn: return QVariant::fromValue(costs.temporary); case LocationColumn: - case SymbolColumn: - case BinaryColumn: case NUM_COLUMNS: break; } - } else if (role == FilterRole) { - // TODO: optimize this - return QString(symbol.symbol + symbol.binary); } else if (role == Qt::DisplayRole) { switch (static_cast(column)) { case LocationColumn: - return i18nc("%1: function name, %2: binary basename", "%1 in %2", symbol.symbol, symbol.binary); - case SymbolColumn: - return symbol.symbol; - case BinaryColumn: - return symbol.binary; + return Util::toString(symbol, *m_resultData, Util::Short); case PeakColumn: return Util::formatBytes(costs.peak); case LeakedColumn: @@ -311,7 +243,7 @@ class SymbolCostModelImpl : public HashModel } else if (role == SymbolRole) { return QVariant::fromValue(symbol); } else if (role == Qt::ToolTipRole) { - return Util::formatTooltip(symbol, costs, m_totalCosts); + return Util::formatTooltip(symbol, costs, *m_resultData); } return {}; @@ -325,7 +257,7 @@ class SymbolCostModelImpl : public HashModel private: virtual QString symbolHeader() const = 0; - AllocationData m_totalCosts; + std::shared_ptr m_resultData; }; class CallerModel : public SymbolCostModelImpl @@ -359,9 +291,9 @@ class LocationCostModelImpl : public HashModel virtual ~LocationCostModelImpl() = default; - void setResults(const LocationCostMap& map, const AllocationData& totalCosts) + void setResults(const LocationCostMap& map, std::shared_ptr resultData) { - m_totalCosts = totalCosts; + m_resultData = std::move(resultData); HashModel::setRows(map); } @@ -387,7 +319,7 @@ class LocationCostModelImpl : public HashModel { SortRole = Qt::UserRole, TotalCostRole, - FilterRole, + ResultDataRole, LocationRole }; @@ -467,7 +399,7 @@ class LocationCostModelImpl : public HashModel if (role == SortRole) { switch (static_cast(column)) { case LocationColumn: - return location.toString(); + return Util::toString(location, *m_resultData, Util::Long); case SelfAllocationsColumn: // NOTE: we sort by unsigned absolute value return QVariant::fromValue(std::abs(costs.selfCost.allocations)); @@ -492,26 +424,24 @@ class LocationCostModelImpl : public HashModel switch (static_cast(column)) { case SelfAllocationsColumn: case InclusiveAllocationsColumn: - return QVariant::fromValue(m_totalCosts.allocations); + return QVariant::fromValue(m_resultData->totalCosts().allocations); case SelfTemporaryColumn: case InclusiveTemporaryColumn: - return QVariant::fromValue(m_totalCosts.temporary); + return QVariant::fromValue(m_resultData->totalCosts().temporary); case SelfPeakColumn: case InclusivePeakColumn: - return QVariant::fromValue(m_totalCosts.peak); + return QVariant::fromValue(m_resultData->totalCosts().peak); case SelfLeakedColumn: case InclusiveLeakedColumn: - return QVariant::fromValue(m_totalCosts.leaked); + return QVariant::fromValue(m_resultData->totalCosts().leaked); case LocationColumn: case NUM_COLUMNS: break; } - } else if (role == FilterRole) { - return location.toString(); } else if (role == Qt::DisplayRole) { switch (static_cast(column)) { case LocationColumn: - return Util::basename(location.toString()); + return Util::toString(location, *m_resultData, Util::Short); case SelfAllocationsColumn: return QVariant::fromValue(costs.selfCost.allocations); case SelfTemporaryColumn: @@ -533,8 +463,10 @@ class LocationCostModelImpl : public HashModel } } else if (role == LocationRole) { return QVariant::fromValue(location); + } else if (role == ResultDataRole) { + return QVariant::fromValue(m_resultData.get()); } else if (role == Qt::ToolTipRole) { - return Util::formatTooltip(location, costs.selfCost, costs.inclusiveCost, m_totalCosts); + return Util::formatTooltip(location, costs.selfCost, costs.inclusiveCost, *m_resultData); } return {}; @@ -546,7 +478,7 @@ class LocationCostModelImpl : public HashModel } private: - AllocationData m_totalCosts; + std::shared_ptr m_resultData; }; class SourceMapModel : public LocationCostModelImpl diff --git a/src/analyze/gui/chartmodel.cpp b/src/analyze/gui/chartmodel.cpp index 940e87cf..35ff1252 100644 --- a/src/analyze/gui/chartmodel.cpp +++ b/src/analyze/gui/chartmodel.cpp @@ -1,26 +1,13 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "chartmodel.h" #include #include -#include #include #include @@ -29,16 +16,24 @@ #include "util.h" +#include + namespace { QColor colorForColumn(int column, int columnCount) { - return QColor::fromHsv((double(column + 1) / columnCount) * 255, 255, 255); + // The total cost graph (column 0) is always red. + if (column == 0) { + return Qt::red; + } else { + return QColor::fromHsv((double(column + 1) / columnCount) * 255, 255, 255); + } } } ChartModel::ChartModel(Type type, QObject* parent) : QAbstractTableModel(parent) , m_type(type) + , m_maxDatasetCount(11) { qRegisterMetaType(); } @@ -50,30 +45,75 @@ ChartModel::Type ChartModel::type() const return m_type; } +QString ChartModel::typeString() const +{ + switch (m_type) { + case Allocations: + return i18n("Memory Allocations"); + case Consumed: + return i18n("Memory Consumed"); + case Temporary: + return i18n("Temporary Allocations"); + default: + return QString(); + } +} + QVariant ChartModel::headerData(int section, Qt::Orientation orientation, int role) const { - Q_ASSERT(orientation == Qt::Horizontal || section < columnCount()); - if (orientation == Qt::Horizontal) { - if (role == KChart::DatasetPenRole) { - return QVariant::fromValue(m_columnDataSetPens.at(section)); - } else if (role == KChart::DatasetBrushRole) { - return QVariant::fromValue(m_columnDataSetBrushes.at(section)); - } + if (section < 0 || section >= columnCount() || orientation != Qt::Horizontal) { + return {}; + } - if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { - if (section == 0) { - return i18n("Elapsed Time"); - } + if (role == KChart::DatasetPenRole) { + return QVariant::fromValue(m_columnDataSetPens.at(section)); + } else if (role == KChart::DatasetBrushRole) { + return QVariant::fromValue(m_columnDataSetBrushes.at(section)); + } + + if (role == Qt::ToolTipRole) { + if (section == 0) { + return i18n("Elapsed Time"); + } + return typeString(); + } else if (role == Qt::DisplayRole) { + if (section == 0) { switch (m_type) { case Allocations: - return i18n("Memory Allocations"); + return i18n("Total Memory Allocations"); case Consumed: - return i18n("Memory Consumed"); + return i18n("Total Memory Consumption"); case Temporary: - return i18n("Temporary Allocations"); + return i18n("Total Temporary Allocations"); } + } else { + auto id = m_data.labels.value(section / 2).functionId; + QString label = m_data.resultData->string(id); + + // Experimental symbol name shortening, currently only truncating + // and left-justified labels. The length is also fixed and should + // be adjusted later on. + // + // The justified text is also a workaround to setTextAlignment as + // this does not seem to work on KChartLegend objects. This might + // be because it is not supported for these instances, as the re- + // ference suggests: https://doc.qt.io/qt-6/stylesheet-reference.html + // (see "text-align" entry). + int symbolNameLength = 60; + + if (label.size() < symbolNameLength) { + label = label.leftJustified(symbolNameLength); + } else if (label.size() > symbolNameLength) { + label.truncate(symbolNameLength - 3); + label = label.leftJustified(symbolNameLength, QLatin1Char('.')); + } + + label = label.rightJustified(symbolNameLength + 1); + + return i18n("%1", label); } } + return {}; } @@ -120,8 +160,7 @@ QVariant ChartModel::data(const QModelIndex& index, int role) const if (role == Qt::ToolTipRole) { const QString time = Util::formatTime(data.timeStamp); auto byteCost = [cost]() -> QString { - KFormat format; - const auto formatted = format.formatByteSize(cost, 1, KFormat::MetricBinaryDialect); + const auto formatted = Util::formatBytes(cost); if (cost > 1024) { return i18nc("%1: the formatted byte size, e.g. \"1.2KB\", %2: the raw byte size, e.g. \"1300\"", "%1 (%2 bytes)", formatted, cost); @@ -139,7 +178,7 @@ QVariant ChartModel::data(const QModelIndex& index, int role) const return i18n("%1 consumed in total after %2", byteCost(), time); } } else { - const auto label = m_data.labels.value(column).toHtmlEscaped(); + auto label = Util::toString(m_data.labels.value(column), *m_data.resultData, Util::Long); switch (m_type) { case Allocations: return i18n("%2 allocations after %3 from:

= 0); + + int currentColumns = qMin(m_data.labels.size(), m_maxDatasetCount); + int newColumnCount = qMin(m_data.labels.size(), count); + + if (newColumnCount == currentColumns) { + return; + } else if (newColumnCount < currentColumns) { + beginRemoveColumns(QModelIndex(), newColumnCount * 2, currentColumns * 2 - 1); + } else { + beginInsertColumns(QModelIndex(), currentColumns * 2, newColumnCount * 2 - 1); + } + + m_maxDatasetCount = count; + resetColors(); + + if (newColumnCount < currentColumns) { + endRemoveColumns(); + } else { + endInsertColumns(); + } + Q_ASSERT(columnCount() == newColumnCount * 2); +} + +void ChartModel::resetColors() { - Q_ASSERT(m_data.labels.size() < ChartRows::MAX_NUM_COST); - beginResetModel(); - m_data = data; m_columnDataSetBrushes.clear(); m_columnDataSetPens.clear(); const auto columns = columnCount(); @@ -188,6 +250,15 @@ void ChartModel::resetData(const ChartData& data) m_columnDataSetBrushes << QBrush(color); m_columnDataSetPens << QPen(color); } +} + +void ChartModel::resetData(const ChartData& data) +{ + Q_ASSERT(data.resultData); + Q_ASSERT(data.labels.size() < ChartRows::MAX_NUM_COST); + beginResetModel(); + m_data = data; + resetColors(); endResetModel(); } @@ -199,3 +270,25 @@ void ChartModel::clearData() m_columnDataSetPens = {}; endResetModel(); } + +struct CompareClosestToTime +{ + bool operator()(const qint64& lhs, const ChartRows& rhs) const + { + return lhs > rhs.timeStamp; + } + bool operator()(const ChartRows& lhs, const qint64& rhs) const + { + return lhs.timeStamp > rhs; + } +}; + +qint64 ChartModel::totalCostAt(qint64 timeStamp) const +{ + auto it = std::lower_bound(m_data.rows.rbegin(), m_data.rows.rend(), timeStamp, CompareClosestToTime()); + if (it == m_data.rows.rend()) + return 0; + return it->cost[0]; +} + +#include "moc_chartmodel.cpp" diff --git a/src/analyze/gui/chartmodel.h b/src/analyze/gui/chartmodel.h index e480d5dd..be197680 100644 --- a/src/analyze/gui/chartmodel.h +++ b/src/analyze/gui/chartmodel.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef CHARTMODEL_H #define CHARTMODEL_H @@ -24,6 +12,10 @@ #include #include +#include "resultdata.h" + +#include + struct ChartRows { ChartRows() @@ -32,7 +24,7 @@ struct ChartRows } enum { - MAX_NUM_COST = 20 + MAX_NUM_COST = 21 }; // time in ms qint64 timeStamp = 0; @@ -43,7 +35,8 @@ Q_DECLARE_TYPEINFO(ChartRows, Q_MOVABLE_TYPE); struct ChartData { QVector rows; - QHash labels; + QHash labels; + std::shared_ptr resultData; }; Q_DECLARE_METATYPE(ChartData) Q_DECLARE_TYPEINFO(ChartData, Q_MOVABLE_TYPE); @@ -62,6 +55,7 @@ class ChartModel : public QAbstractTableModel virtual ~ChartModel(); Type type() const; + QString typeString() const; QVariant headerData(int section, Qt::Orientation orientation = Qt::Horizontal, int role = Qt::DisplayRole) const override; @@ -69,17 +63,28 @@ class ChartModel : public QAbstractTableModel int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; + int maximumDatasetCount() const + { + return m_maxDatasetCount; + } + void setMaximumDatasetCount(int count); + + qint64 totalCostAt(qint64 timeStamp) const; + public slots: void resetData(const ChartData& data); void clearData(); private: + void resetColors(); + ChartData m_data; Type m_type; // we cache the pens and brushes as constructing them requires allocations // otherwise QVector m_columnDataSetPens; QVector m_columnDataSetBrushes; + int m_maxDatasetCount; }; #endif // CHARTMODEL_H diff --git a/src/analyze/gui/chartproxy.cpp b/src/analyze/gui/chartproxy.cpp index 9f4d7d27..bec1ffcf 100644 --- a/src/analyze/gui/chartproxy.cpp +++ b/src/analyze/gui/chartproxy.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "chartproxy.h" @@ -36,3 +24,5 @@ bool ChartProxy::filterAcceptsColumn(int sourceColumn, const QModelIndex& /*sour return false; return true; } + +#include "moc_chartproxy.cpp" diff --git a/src/analyze/gui/chartproxy.h b/src/analyze/gui/chartproxy.h index ccb01c16..ab1da3b4 100644 --- a/src/analyze/gui/chartproxy.h +++ b/src/analyze/gui/chartproxy.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef CHARTPROXY_H #define CHARTPROXY_H diff --git a/src/analyze/gui/chartwidget.cpp b/src/analyze/gui/chartwidget.cpp index aeced615..a5f60dd7 100644 --- a/src/analyze/gui/chartwidget.cpp +++ b/src/analyze/gui/chartwidget.cpp @@ -1,23 +1,24 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "chartwidget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -30,18 +31,48 @@ #include #include #include +#include #include -#include #include #include "chartmodel.h" #include "chartproxy.h" #include "util.h" +#include +#include + using namespace KChart; namespace { +KChart::TextAttributes fixupTextAttributes(KChart::TextAttributes attributes, const QPen& foreground, float pointSize) +{ + attributes.setPen(foreground); + auto fontSize = attributes.fontSize(); + fontSize.setAbsoluteValue(pointSize); + attributes.setFontSize(fontSize); + return attributes; +} + +QPointF localPos(QMouseEvent* event) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + return event->localPos(); +#else + return event->position(); +#endif +} + +QPoint globalPos(QMouseEvent* event) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + return event->globalPos(); +#else + return event->globalPosition().toPoint(); +#endif +} + class TimeAxis : public CartesianAxis { Q_OBJECT @@ -53,8 +84,22 @@ class TimeAxis : public CartesianAxis const QString customizedLabel(const QString& label) const override { - return Util::formatTime(label.toLongLong()); + const auto time = label.toLongLong(); + if (m_summaryData.filterParameters.isFilteredByTime(m_summaryData.totalTime)) { + return Util::formatTime(time) + QLatin1Char('\n') + + Util::formatTime(time - m_summaryData.filterParameters.minTime); + } + return Util::formatTime(time); + } + + void setSummaryData(const SummaryData& summaryData) + { + m_summaryData = summaryData; + update(); } + +private: + SummaryData m_summaryData; }; class SizeAxis : public CartesianAxis @@ -68,33 +113,164 @@ class SizeAxis : public CartesianAxis const QString customizedLabel(const QString& label) const override { - KFormat format(QLocale::system()); - return format.formatByteSize(label.toDouble(), 1, KFormat::MetricBinaryDialect); + return Util::formatBytes(label.toLongLong()); } }; + +/// see also ProxyStyle which is responsible for unsetting SH_RubberBand_Mask +class ChartRubberBand : public QRubberBand +{ + Q_OBJECT +public: + explicit ChartRubberBand(QWidget* parent) + : QRubberBand(QRubberBand::Rectangle, parent) + { + } + ~ChartRubberBand() = default; + +protected: + void paintEvent(QPaintEvent* event) override + { + auto brush = palette().highlight(); + if (brush != m_lastBrush) { + auto color = brush.color(); + color.setAlpha(128); + brush.setColor(color); + m_cachedBrush = brush; + } else { + brush = m_cachedBrush; + } + + QPainter painter(this); + painter.fillRect(event->rect(), brush); + } + +private: + QBrush m_lastBrush; + QBrush m_cachedBrush; +}; } ChartWidget::ChartWidget(QWidget* parent) : QWidget(parent) , m_chart(new Chart(this)) + , m_legend(new Legend(m_chart)) + , m_rubberBand(new ChartRubberBand(this)) { + auto m_chartToolBar = new QToolBar(this); + + auto m_exportAsButton = new QPushButton(i18n("Export As..."), this); + connect(m_exportAsButton, &QPushButton::released, this, &ChartWidget::saveAs); + + auto m_showLegend = new QCheckBox(i18n("Show legend"), this); + m_showLegend->setChecked(false); + connect(m_showLegend, &QCheckBox::toggled, this, [=](bool show) { + m_legend->setVisible(show); + m_chart->update(); + }); + + auto m_showTotal = new QCheckBox(i18n("Show total cost graph"), this); + m_showTotal->setChecked(true); + connect(m_showTotal, &QCheckBox::toggled, this, [=](bool show) { + m_totalPlotter->setHidden(!show); + m_chart->update(); + }); + m_legend->setVisible(m_showLegend->checkState()); + + auto m_showDetailed = new QCheckBox(i18n("Show detailed cost graph"), this); + m_showDetailed->setChecked(true); + connect(m_showDetailed, &QCheckBox::toggled, this, [=](bool show) { + m_detailedPlotter->setHidden(!show); + m_chart->update(); + }); + + auto stackedLabel = new QLabel(i18n("Stacked diagrams:")); + m_stackedDiagrams = new QSpinBox(this); + m_stackedDiagrams->setMinimum(0); + m_stackedDiagrams->setMaximum(50); + connect(m_stackedDiagrams, qOverload(&QSpinBox::valueChanged), this, + [=](int value) { m_model->setMaximumDatasetCount(value + 1); }); + + m_chartToolBar->addWidget(m_exportAsButton); + m_chartToolBar->addSeparator(); + m_chartToolBar->addWidget(m_showLegend); + m_chartToolBar->addSeparator(); + m_chartToolBar->addWidget(m_showTotal); + m_chartToolBar->addWidget(m_showDetailed); + m_chartToolBar->addSeparator(); + m_chartToolBar->addWidget(stackedLabel); + m_chartToolBar->addWidget(m_stackedDiagrams); + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(m_chartToolBar); layout->addWidget(m_chart); setLayout(layout); auto* coordinatePlane = dynamic_cast(m_chart->coordinatePlane()); Q_ASSERT(coordinatePlane); - coordinatePlane->setRubberBandZoomingEnabled(true); coordinatePlane->setAutoAdjustGridToZoom(true); + connect(coordinatePlane, &CartesianCoordinatePlane::needUpdate, this, &ChartWidget::updateRubberBand); + + m_chart->setCursor(Qt::IBeamCursor); + m_chart->setMouseTracking(true); + m_chart->installEventFilter(this); + + m_chart->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_chart, &QWidget::customContextMenuRequested, this, [this](const QPoint& point) { + if (!m_model) + return; + + const auto isFiltered = m_summaryData.filterParameters.isFilteredByTime(m_summaryData.totalTime); + if (!m_selection && !isFiltered) + return; + + auto* menu = new QMenu(this); + menu->setAttribute(Qt::WA_DeleteOnClose, true); + + if (m_selection) { + auto* reparse = menu->addAction(QIcon::fromTheme(QStringLiteral("timeline-use-zone-on")), + i18n("Filter In On Selection")); + connect(reparse, &QAction::triggered, this, [this]() { + const auto startTime = std::min(m_selection.start, m_selection.end); + const auto endTime = std::max(m_selection.start, m_selection.end); + emit filterRequested(startTime, endTime); + }); + } + + if (isFiltered) { + auto* reset = + menu->addAction(QIcon::fromTheme(QStringLiteral("timeline-use-zone-off")), i18n("Reset Filter")); + connect(reset, &QAction::triggered, this, + [this]() { emit filterRequested(0, std::numeric_limits::max()); }); + } + + menu->popup(m_chart->mapToGlobal(point)); + }); } ChartWidget::~ChartWidget() = default; +void ChartWidget::setSummaryData(const SummaryData& summaryData) +{ + m_summaryData = summaryData; + updateAxesTitle(); + if (m_bottomAxis) { + static_cast(m_bottomAxis)->setSummaryData(summaryData); + } +} + void ChartWidget::setModel(ChartModel* model, bool minimalMode) { + if (m_model == model) + return; + m_model = model; + auto* coordinatePlane = dynamic_cast(m_chart->coordinatePlane()); Q_ASSERT(coordinatePlane); - foreach (auto diagram, coordinatePlane->diagrams()) { + const auto diagrams = coordinatePlane->diagrams(); + for (auto diagram : diagrams) { coordinatePlane->takeDiagram(diagram); delete diagram; } @@ -105,71 +281,198 @@ void ChartWidget::setModel(ChartModel* model, bool minimalMode) coordinatePlane->setGlobalGridAttributes(grid); } - switch (model->type()) { - case ChartModel::Consumed: - setToolTip(i18n("Shows the heap memory consumption over time.")); - break; - case ChartModel::Allocations: - setToolTip(i18n("Shows number of memory allocations over time.")); - break; - case ChartModel::Temporary: - setToolTip(i18n("Shows number of temporary memory allocations over time. " - "A temporary allocation is one that is followed immediately by its " - "corresponding deallocation, without other allocations happening " - "in-between.")); - break; + KColorScheme scheme(QPalette::Active, KColorScheme::Window); + QPen foreground(scheme.foreground().color()); + + { + KChart::GridAttributes grid = coordinatePlane->gridAttributes(Qt::Horizontal); + // Do not align view on main grid line, stretch grid to match datasets + grid.setAdjustBoundsToGrid(false, false); + coordinatePlane->setGridAttributes(Qt::Horizontal, grid); + + m_legend->setOrientation(Qt::Vertical); + m_legend->setTitleText(QString()); + m_legend->setSortOrder(Qt::DescendingOrder); + + RelativePosition relPos; + relPos.setReferenceArea(coordinatePlane); + relPos.setReferencePosition(Position::NorthWest); + relPos.setAlignment(Qt::AlignTop | Qt::AlignLeft | Qt::AlignAbsolute); + relPos.setHorizontalPadding(Measure(3.0, KChartEnums::MeasureCalculationModeAbsolute)); + relPos.setVerticalPadding(Measure(3.0, KChartEnums::MeasureCalculationModeAbsolute)); + + m_legend->setFloatingPosition(relPos); + m_legend->setTextAlignment(Qt::AlignLeft | Qt::AlignAbsolute); + + m_chart->addLegend(m_legend); + + BackgroundAttributes bkgAtt = m_legend->backgroundAttributes(); + QColor background = scheme.background(KColorScheme::AlternateBackground).color(); + background.setAlpha(200); + bkgAtt.setBrush(QBrush(background)); + bkgAtt.setVisible(true); + + TextAttributes textAttr = fixupTextAttributes(m_legend->textAttributes(), foreground, font().pointSizeF() - 2); + QFont legendFont(QStringLiteral("monospace")); + legendFont.setStyleHint(QFont::TypeWriter); + textAttr.setFont(legendFont); + + m_legend->setBackgroundAttributes(bkgAtt); + m_legend->setTextAttributes(textAttr); } { - auto totalPlotter = new Plotter(this); - totalPlotter->setAntiAliasing(true); + m_totalPlotter = new Plotter(this); + m_totalPlotter->setAntiAliasing(true); auto totalProxy = new ChartProxy(true, this); totalProxy->setSourceModel(model); - totalPlotter->setModel(totalProxy); - totalPlotter->setType(Plotter::Stacked); - - KColorScheme scheme(QPalette::Active, KColorScheme::Window); - const QPen foreground(scheme.foreground().color()); - auto bottomAxis = new TimeAxis(totalPlotter); - auto axisTextAttributes = bottomAxis->textAttributes(); - axisTextAttributes.setPen(foreground); - bottomAxis->setTextAttributes(axisTextAttributes); - auto axisTitleTextAttributes = bottomAxis->titleTextAttributes(); - axisTitleTextAttributes.setPen(foreground); - auto fontSize = axisTitleTextAttributes.fontSize(); - fontSize.setCalculationMode(KChartEnums::MeasureCalculationModeAbsolute); - if (minimalMode) { - fontSize.setValue(font().pointSizeF() - 2); - } else { - fontSize.setValue(font().pointSizeF() + 2); - } - axisTitleTextAttributes.setFontSize(fontSize); - bottomAxis->setTitleTextAttributes(axisTitleTextAttributes); - bottomAxis->setTitleText(model->headerData(0).toString()); - bottomAxis->setPosition(CartesianAxis::Bottom); - totalPlotter->addAxis(bottomAxis); + m_totalPlotter->setModel(totalProxy); + m_totalPlotter->setType(Plotter::Stacked); + + m_bottomAxis = new TimeAxis(m_totalPlotter); + const auto axisTextAttributes = + fixupTextAttributes(m_bottomAxis->textAttributes(), foreground, font().pointSizeF() - 2); + m_bottomAxis->setTextAttributes(axisTextAttributes); + const auto axisTitleTextAttributes = fixupTextAttributes(m_bottomAxis->titleTextAttributes(), foreground, + font().pointSizeF() + (minimalMode ? (-2) : (+2))); + m_bottomAxis->setTitleTextAttributes(axisTitleTextAttributes); + m_bottomAxis->setPosition(CartesianAxis::Bottom); + m_totalPlotter->addAxis(m_bottomAxis); - CartesianAxis* rightAxis = model->type() == ChartModel::Allocations || model->type() == ChartModel::Temporary - ? new CartesianAxis(totalPlotter) - : new SizeAxis(totalPlotter); - rightAxis->setTextAttributes(axisTextAttributes); - rightAxis->setTitleTextAttributes(axisTitleTextAttributes); - rightAxis->setTitleText(model->headerData(1).toString()); - rightAxis->setPosition(CartesianAxis::Right); - totalPlotter->addAxis(rightAxis); + m_rightAxis = model->type() == ChartModel::Allocations || model->type() == ChartModel::Temporary + ? new CartesianAxis(m_totalPlotter) + : new SizeAxis(m_totalPlotter); + m_rightAxis->setTextAttributes(axisTextAttributes); + m_rightAxis->setTitleTextAttributes(axisTitleTextAttributes); + m_rightAxis->setPosition(CartesianAxis::Right); + m_totalPlotter->addAxis(m_rightAxis); - coordinatePlane->addDiagram(totalPlotter); + coordinatePlane->addDiagram(m_totalPlotter); + + m_legend->addDiagram(m_totalPlotter); } { - auto plotter = new Plotter(this); - plotter->setAntiAliasing(true); - plotter->setType(Plotter::Stacked); + m_detailedPlotter = new Plotter(this); + m_detailedPlotter->setAntiAliasing(true); + m_detailedPlotter->setType(Plotter::Stacked); auto proxy = new ChartProxy(false, this); proxy->setSourceModel(model); - plotter->setModel(proxy); - coordinatePlane->addDiagram(plotter); + m_detailedPlotter->setModel(proxy); + coordinatePlane->addDiagram(m_detailedPlotter); + + m_legend->addDiagram(m_detailedPlotter); + } + + m_legend->hide(); + + // If the dataset has 10 entries, one is for the total plot and the + // remaining ones are for the detailed plot. We want to only change + // the number of detailed plots, so we have to correct it. + int maximumDatasetCount = m_model->maximumDatasetCount(); + m_stackedDiagrams->setValue(maximumDatasetCount - 1); + + updateToolTip(); + updateAxesTitle(); +} + +void ChartWidget::saveAs() +{ + const auto saveFilename = + QFileDialog::getSaveFileName(this, i18n("Save %1", windowTitle()), QString(), + i18n("Raster Image (*.png *.jpg *.tiff);;Vector Image (*.svg)")); + + if (!saveFilename.isEmpty()) { + if (QFileInfo(saveFilename).suffix() == QLatin1String("svg")) { + // vector graphic format + QSvgGenerator generator; + generator.setFileName(saveFilename); + generator.setSize(m_chart->size()); + generator.setViewBox(m_chart->rect()); + + QPainter painter; + painter.begin(&generator); + m_chart->paint(&painter, m_chart->rect()); + painter.end(); + } else if (!m_chart->grab().save(saveFilename)) { + // other format + KMessageBox::error(this, i18n("Failed to save the image to %1", saveFilename)); + } + } +} + +void ChartWidget::updateToolTip() +{ + if (!m_model) + return; + + const auto startTime = std::min(m_selection.start, m_selection.end); + const auto endTime = std::max(m_selection.start, m_selection.end); + + const auto startCost = m_model->totalCostAt(startTime); + const auto endCost = m_model->totalCostAt(endTime); + + QString toolTip; + if (!qFuzzyCompare(startTime, endTime)) { + QTextStream stream(&toolTip); + stream << ""; + stream << i18n(""); + stream << i18n("", Util::formatTime(startTime), + Util::formatTime(endTime), Util::formatTime(endTime - startTime)); + switch (m_model->type()) { + case ChartModel::Consumed: + stream << i18n("", Util::formatBytes(startCost), + Util::formatBytes(endCost), Util::formatBytes(endCost - startCost)); + break; + case ChartModel::Allocations: + stream << i18n("", startCost, endCost, + (endCost - startCost)); + break; + case ChartModel::Temporary: + stream << i18n("", startCost, + endCost, (endCost - startCost)); + break; + } + stream << "
StartEndDelta
Time%1%2%3
Consumed%1%2%3
Allocations%1%2%3
Temporary Allocations%1%2%3
"; + } else { + switch (m_model->type()) { + case ChartModel::Consumed: + toolTip = i18n("Shows the heap memory consumption over time.
Click and drag to select a time range " + "for filtering.
"); + break; + case ChartModel::Allocations: + toolTip = i18n("Shows number of memory allocations over time.
Click and drag to select a time range " + "for filtering.
"); + break; + case ChartModel::Temporary: + toolTip = i18n("Shows number of temporary memory allocations over time. " + "A temporary allocation is one that is followed immediately by its " + "corresponding deallocation, without other allocations happening " + "in-between.
Click and drag to select a time range for filtering.
"); + break; + } + } + + setToolTip(toolTip); +} + +void ChartWidget::updateAxesTitle() +{ + if (!m_model) + return; + + // m_bottomAxis is always time, so we can just write it here instead of in headerData(). + m_bottomAxis->setTitleText(i18n("Elapsed Time")); + m_rightAxis->setTitleText(m_model->typeString()); + + if (m_summaryData.filterParameters.isFilteredByTime(m_summaryData.totalTime)) { + m_bottomAxis->setTitleText( + i18n("%1 (filtered from %2 to %3, Δ%4)", m_bottomAxis->titleText(), + Util::formatTime(m_summaryData.filterParameters.minTime), + Util::formatTime(m_summaryData.filterParameters.maxTime), + Util::formatTime(m_summaryData.filterParameters.maxTime - m_summaryData.filterParameters.minTime))); + m_rightAxis->setTitleText(i18n("%1 (filtered delta)", m_rightAxis->titleText())); } } @@ -178,4 +481,113 @@ QSize ChartWidget::sizeHint() const return {400, 50}; } +void ChartWidget::setSelection(const Range& selection) +{ + if (selection == m_selection || !m_model) + return; + + m_selection = selection; + + updateToolTip(); + updateRubberBand(); + + emit selectionChanged(m_selection); +} + +void ChartWidget::updateRubberBand() +{ + if (!m_selection || !m_model) { + m_rubberBand->hide(); + return; + } + + auto* coordinatePlane = static_cast(m_chart->coordinatePlane()); + const auto delta = m_chart->pos().x(); + const auto pixelStart = coordinatePlane->translate({m_selection.start, 0}).x() + delta; + const auto pixelEnd = coordinatePlane->translate({m_selection.end, 0}).x() + delta; + auto selectionRect = QRect(QPoint(pixelStart, 0), QPoint(pixelEnd, height() - 1)); + m_rubberBand->setGeometry(selectionRect.normalized()); + m_rubberBand->show(); +} + +bool ChartWidget::eventFilter(QObject* watched, QEvent* event) +{ + Q_ASSERT(watched == m_chart); + + if (!m_model) + return false; + + auto mapPosToTime = [this](const QPointF& pos) { + auto* coordinatePlane = static_cast(m_chart->coordinatePlane()); + return coordinatePlane->translateBack(pos).x(); + }; + + if (auto* mouseEvent = dynamic_cast(event)) { + if (mouseEvent->button() == Qt::LeftButton || mouseEvent->buttons() == Qt::LeftButton) { + const auto time = mapPosToTime(localPos(mouseEvent)); + + auto selection = m_selection; + selection.end = time; + if (event->type() == QEvent::MouseButtonPress) { + selection.start = time; + m_chart->setCursor(Qt::SizeHorCursor); + m_cachedChart = m_chart->grab(); + } else if (event->type() == QEvent::MouseButtonRelease) { + m_chart->setCursor(Qt::IBeamCursor); + m_cachedChart = {}; + } + + setSelection(selection); + QToolTip::showText(globalPos(mouseEvent), toolTip(), this); + return true; + } else if (event->type() == QEvent::MouseMove && !mouseEvent->buttons()) { + updateStatusTip(mapPosToTime(localPos(mouseEvent))); + } + } else if (event->type() == QEvent::Paint && !m_cachedChart.isNull()) { + // use the cached chart while interacting with the rubber band + // otherwise, use the normal paint even as that one is required for + // the mouse mapping etc. to work correctly... + QPainter painter(m_chart); + painter.drawPixmap(m_chart->rect(), m_cachedChart); + return true; + } + return false; +} + +void ChartWidget::updateStatusTip(qint64 time) +{ + if (!m_model) + return; + + const auto text = [=]() { + if (time < 0 || time > m_summaryData.filterParameters.maxTime) { + return i18n("Click and drag to select time range for filtering."); + } + + const auto cost = m_model->totalCostAt(time); + switch (m_model->type()) { + case ChartModel::Consumed: + return i18n("T = %1, Consumed: %2. Click and drag to select time range for filtering.", + Util::formatTime(time), Util::formatBytes(cost)); + break; + case ChartModel::Allocations: + return i18n("T = %1, Allocations: %2. Click and drag to select time range for filtering.", + Util::formatTime(time), cost); + break; + case ChartModel::Temporary: + return i18n("T = %1, Temporary Allocations: %2. Click and drag to select time range for filtering.", + Util::formatTime(time), cost); + break; + } + Q_UNREACHABLE(); + }(); + setStatusTip(text); + + // force update + QStatusTipEvent event(text); + QApplication::sendEvent(this, &event); +} + #include "chartwidget.moc" + +#include "moc_chartwidget.cpp" diff --git a/src/analyze/gui/chartwidget.h b/src/analyze/gui/chartwidget.h index dcf64eac..c04da2e1 100644 --- a/src/analyze/gui/chartwidget.h +++ b/src/analyze/gui/chartwidget.h @@ -1,34 +1,29 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef CHARTWIDGET_H #define CHARTWIDGET_H #include +#include "summarydata.h" + +class QRubberBand; +class QAbstractItemModel; +class QSpinBox; + class ChartModel; namespace KChart { class Chart; +class CartesianAxis; +class Legend; +class Plotter; } -class QAbstractItemModel; - class ChartWidget : public QWidget { Q_OBJECT @@ -40,8 +35,55 @@ class ChartWidget : public QWidget QSize sizeHint() const override; + struct Range + { + float start = -1; + float end = -1; + + bool operator==(const Range& rhs) const + { + return start == rhs.start && end == rhs.end; + } + + explicit operator bool() const + { + return start != end; + } + }; + void setSelection(const Range& range); + Range selection() const + { + return m_selection; + } + + void setSummaryData(const SummaryData& summaryData); + +signals: + void selectionChanged(const Range& range); + void filterRequested(int64_t minTime, int64_t maxTime); + +public slots: + void saveAs(); + private: - KChart::Chart* m_chart; + void updateToolTip(); + void updateStatusTip(qint64 time); + void updateAxesTitle(); + void updateRubberBand(); + bool eventFilter(QObject* watched, QEvent* event) override; + + KChart::Plotter* m_totalPlotter = nullptr; + KChart::Plotter* m_detailedPlotter = nullptr; + QSpinBox* m_stackedDiagrams = nullptr; + KChart::Chart* m_chart = nullptr; + KChart::Legend* m_legend = nullptr; + KChart::CartesianAxis* m_bottomAxis = nullptr; + KChart::CartesianAxis* m_rightAxis = nullptr; + ChartModel* m_model = nullptr; + QRubberBand* m_rubberBand = nullptr; + Range m_selection; + SummaryData m_summaryData; + QPixmap m_cachedChart; }; #endif // CHARTWIDGET_H diff --git a/src/analyze/gui/costdelegate.cpp b/src/analyze/gui/costdelegate.cpp index 366f14e9..12ad70e2 100644 --- a/src/analyze/gui/costdelegate.cpp +++ b/src/analyze/gui/costdelegate.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2016-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "costdelegate.h" @@ -74,3 +62,5 @@ void CostDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, QStyledItemDelegate::paint(painter, option, index); } } + +#include "moc_costdelegate.cpp" diff --git a/src/analyze/gui/costdelegate.h b/src/analyze/gui/costdelegate.h index 351f975c..04cd8f0f 100644 --- a/src/analyze/gui/costdelegate.h +++ b/src/analyze/gui/costdelegate.h @@ -1,20 +1,8 @@ /* - * Copyright 2016-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef COSTDELEGATE_H #define COSTDELEGATE_H diff --git a/src/analyze/gui/costheaderview.cpp b/src/analyze/gui/costheaderview.cpp new file mode 100644 index 00000000..1040ee3a --- /dev/null +++ b/src/analyze/gui/costheaderview.cpp @@ -0,0 +1,113 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include "costheaderview.h" + +#include +#include +#include +#include +#include + +#include + +CostHeaderView::CostHeaderView(QWidget* parent) + : QHeaderView(Qt::Horizontal, parent) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + setSectionsMovable(true); + setFirstSectionMovable(false); +#endif + setDefaultSectionSize(100); + setStretchLastSection(false); + connect(this, &QHeaderView::sectionCountChanged, this, [this]() { resizeColumns(false); }); + connect(this, &QHeaderView::sectionResized, this, [this](int index, int oldSize, int newSize) { + if (m_isResizing) + return; + QScopedValueRollback guard(m_isResizing, true); + if (index != 0) { + // give/take space from first column + resizeSection(0, sectionSize(0) - (newSize - oldSize)); + } else { + // distribute space across all columns + // use actual width as oldSize/newSize isn't reliable here + const auto numSections = count(); + int usedWidth = 0; + for (int i = 0; i < numSections; ++i) + usedWidth += sectionSize(i); + const auto diff = usedWidth - width(); + const auto numVisibleSections = numSections - hiddenSectionCount(); + if (numVisibleSections == 0) + return; + + const auto diffPerSection = diff / numVisibleSections; + const auto extraDiff = diff % numVisibleSections; + for (int i = 1; i < numSections; ++i) { + if (isSectionHidden(i)) { + continue; + } + auto newSize = sectionSize(i) - diffPerSection; + if (i == numSections - 1) + newSize -= extraDiff; + resizeSection(i, newSize); + } + } + }); + + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &QHeaderView::customContextMenuRequested, this, [this](const QPoint& pos) { + const auto numSections = count(); + + QMenu menu; + auto resetSizes = menu.addAction(tr("Reset Column Sizes")); + connect(resetSizes, &QAction::triggered, this, [this]() { resizeColumns(true); }); + + if (numSections > 1) { + auto* subMenu = menu.addMenu(tr("Visible Columns")); + for (int i = 1; i < numSections; ++i) { + auto* action = subMenu->addAction(model()->headerData(i, Qt::Horizontal).toString()); + action->setCheckable(true); + action->setChecked(!isSectionHidden(i)); + connect(action, &QAction::toggled, this, [this, i](bool visible) { setSectionHidden(i, !visible); }); + } + } + + menu.exec(mapToGlobal(pos)); + }); +} + +CostHeaderView::~CostHeaderView() = default; + +void CostHeaderView::resizeEvent(QResizeEvent* event) +{ + QHeaderView::resizeEvent(event); + resizeColumns(false); +} + +void CostHeaderView::resizeColumns(bool reset) +{ + const auto numColumns = count(); + if (!numColumns) { + return; + } + + QScopedValueRollback guard(m_isResizing, true); + auto availableWidth = width(); + const auto defaultSize = defaultSectionSize(); + + for (int i = numColumns - 1; i >= 0; --i) { + if (i == 0) { + resizeSection(i, std::max(availableWidth, defaultSize)); + } else if (reset) { + resizeSection(i, defaultSize); + } + if (!isSectionHidden(i)) { + availableWidth -= sectionSize(i); + } + } +} + +#include "moc_costheaderview.cpp" diff --git a/src/analyze/gui/costheaderview.h b/src/analyze/gui/costheaderview.h new file mode 100644 index 00000000..7ec40edf --- /dev/null +++ b/src/analyze/gui/costheaderview.h @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#pragma once + +#include + +class CostHeaderView : public QHeaderView +{ + Q_OBJECT +public: + explicit CostHeaderView(QWidget* parent = nullptr); + ~CostHeaderView(); + +private: + void resizeEvent(QResizeEvent* event) override; + void resizeColumns(bool reset); + + bool m_isResizing = false; +}; diff --git a/src/analyze/gui/flamegraph.cpp b/src/analyze/gui/flamegraph.cpp index f171d01d..cf230292 100644 --- a/src/analyze/gui/flamegraph.cpp +++ b/src/analyze/gui/flamegraph.cpp @@ -1,27 +1,17 @@ /* - * Copyright 2015-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "flamegraph.h" #include #include +#include #include +#include #include #include #include @@ -33,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +34,7 @@ #include #include +#include "resultdata.h" #include "util.h" enum CostType @@ -67,8 +59,10 @@ enum SearchMatchType class FrameGraphicsItem : public QGraphicsRectItem { public: - FrameGraphicsItem(const qint64 cost, CostType costType, const Symbol& symbol, FrameGraphicsItem* parent = nullptr); - FrameGraphicsItem(const qint64 cost, const Symbol& symbol, FrameGraphicsItem* parent); + FrameGraphicsItem(const qint64 cost, CostType costType, const Symbol& symbol, + std::shared_ptr resultData, FrameGraphicsItem* parent = nullptr); + FrameGraphicsItem(const qint64 cost, const Symbol& symbol, std::shared_ptr resultData, + FrameGraphicsItem* parent); qint64 cost() const; void setCost(qint64 cost); @@ -77,6 +71,8 @@ class FrameGraphicsItem : public QGraphicsRectItem void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override; QString description() const; + + bool match(const QString& searchValue) const; void setSearchMatchType(SearchMatchType matchType); protected: @@ -84,6 +80,7 @@ class FrameGraphicsItem : public QGraphicsRectItem void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override; private: + std::shared_ptr m_resultData; qint64 m_cost; Symbol m_symbol; CostType m_costType; @@ -94,8 +91,9 @@ class FrameGraphicsItem : public QGraphicsRectItem Q_DECLARE_METATYPE(FrameGraphicsItem*) FrameGraphicsItem::FrameGraphicsItem(const qint64 cost, CostType costType, const Symbol& symbol, - FrameGraphicsItem* parent) + std::shared_ptr resultData, FrameGraphicsItem* parent) : QGraphicsRectItem(parent) + , m_resultData(std::move(resultData)) , m_cost(cost) , m_symbol(symbol) , m_costType(costType) @@ -105,8 +103,9 @@ FrameGraphicsItem::FrameGraphicsItem(const qint64 cost, CostType costType, const setAcceptHoverEvents(true); } -FrameGraphicsItem::FrameGraphicsItem(const qint64 cost, const Symbol& symbol, FrameGraphicsItem* parent) - : FrameGraphicsItem(cost, parent->m_costType, symbol, parent) +FrameGraphicsItem::FrameGraphicsItem(const qint64 cost, const Symbol& symbol, + std::shared_ptr resultData, FrameGraphicsItem* parent) + : FrameGraphicsItem(cost, parent->m_costType, symbol, std::move(resultData), parent) { } @@ -165,10 +164,29 @@ void FrameGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* painter->setPen(pen); } + auto label = [this]() { + if (m_symbol.isValid()) { + return m_resultData->string(m_symbol.functionId); + } + + // root + switch (m_costType) { + case Allocations: + return i18n("%1 allocations in total", m_cost); + case Temporary: + return i18n("%1 temporary allocations in total", m_cost); + case Peak: + return i18n("%1 peak memory consumption", Util::formatBytes(m_cost)); + case Leaked: + return i18n("%1 leaked in total", Util::formatBytes(m_cost)); + } + Q_UNREACHABLE(); + }(); + const int height = rect().height(); painter->drawText(margin + rect().x(), rect().y(), width, height, Qt::AlignVCenter | Qt::AlignLeft | Qt::TextSingleLine, - option->fontMetrics.elidedText(m_symbol.symbol, Qt::ElideRight, width)); + option->fontMetrics.elidedText(label, Qt::ElideRight, width)); if (m_searchMatch == NoMatch) { painter->setPen(oldPen); @@ -191,14 +209,14 @@ void FrameGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) QString FrameGraphicsItem::description() const { + const auto symbol = Util::toString(m_symbol, *m_resultData, Util::Short); + // we build the tooltip text on demand, which is much faster than doing that // for potentially thousands of items when we load the data - const auto symbol = i18nc("%1: function, %2: binary", "%1 (%2)", m_symbol.symbol, m_symbol.binary); if (!parentItem()) { - return m_symbol.symbol; + return symbol; } - KFormat format; qint64 totalCost = 0; { auto item = this; @@ -223,18 +241,26 @@ QString FrameGraphicsItem::description() const case Peak: tooltip = i18nc("%1: peak consumption in bytes, %2: relative number, %3: " "function label", - "%1 (%2%) contribution to peak consumption in %3 and below.", - format.formatByteSize(m_cost, 1, KFormat::MetricBinaryDialect), fraction, symbol); + "%1 (%2%) contribution to peak consumption in %3 and below.", Util::formatBytes(m_cost), + fraction, symbol); break; case Leaked: tooltip = i18nc("%1: leaked bytes, %2: relative number, %3: function label", "%1 (%2%) leaked in %3 and below.", - format.formatByteSize(m_cost, 1, KFormat::MetricBinaryDialect), fraction, symbol); + Util::formatBytes(m_cost), fraction, symbol); break; } return tooltip; } +bool FrameGraphicsItem::match(const QString& searchValue) const +{ + auto match = [&](StringIndex index) { + return m_resultData->string(index).contains(searchValue, Qt::CaseInsensitive); + }; + return match(m_symbol.functionId) || match(m_symbol.moduleId); +} + void FrameGraphicsItem::setSearchMatchType(SearchMatchType matchType) { if (m_searchMatch != matchType) { @@ -276,7 +302,8 @@ void layoutItems(FrameGraphicsItem* parent) const qreal y = pos.y() - h - y_margin; qreal x = pos.x(); - foreach (auto child, parent->childItems()) { + const auto children = parent->childItems(); + for (auto child : children) { auto frameChild = static_cast(child); const qreal w = maxWidth * double(frameChild->cost()) / parent->cost(); frameChild->setVisible(w > 1); @@ -290,7 +317,7 @@ void layoutItems(FrameGraphicsItem* parent) FrameGraphicsItem* findItemBySymbol(const QList& items, const Symbol& symbol) { - foreach (auto item_, items) { + for (auto item_ : items) { auto item = static_cast(item_); if (item->symbol() == symbol) { return item; @@ -302,24 +329,25 @@ FrameGraphicsItem* findItemBySymbol(const QList& items, const Sy /** * Convert the top-down graph into a tree of FrameGraphicsItem. */ -void toGraphicsItems(const QVector& data, FrameGraphicsItem* parent, int64_t AllocationData::*member, - const double costThreshold, bool collapseRecursion) +void toGraphicsItems(const std::shared_ptr& resultData, const QVector& data, + FrameGraphicsItem* parent, int64_t AllocationData::*member, const double costThreshold, + bool collapseRecursion) { - foreach (const auto& row, data) { - if (collapseRecursion && row.symbol.symbol != unresolvedFunctionName() && row.symbol == parent->symbol()) { - toGraphicsItems(row.children, parent, member, costThreshold, collapseRecursion); + for (const auto& row : data) { + if (collapseRecursion && row.symbol.functionId && row.symbol == parent->symbol()) { + toGraphicsItems(resultData, row.children, parent, member, costThreshold, collapseRecursion); continue; } auto item = findItemBySymbol(parent->childItems(), row.symbol); if (!item) { - item = new FrameGraphicsItem(row.cost.*member, row.symbol, parent); + item = new FrameGraphicsItem(row.cost.*member, row.symbol, resultData, parent); item->setPen(parent->pen()); item->setBrush(brush()); } else { item->setCost(item->cost() + row.cost.*member); } if (item->cost() > costThreshold) { - toGraphicsItems(row.children, item, member, costThreshold, collapseRecursion); + toGraphicsItems(resultData, row.children, item, member, costThreshold, collapseRecursion); } } } @@ -339,39 +367,19 @@ int64_t AllocationData::*memberForType(CostType type) Q_UNREACHABLE(); } -FrameGraphicsItem* parseData(const QVector& topDownData, CostType type, double costThreshold, - bool collapseRecursion) +FrameGraphicsItem* parseData(const TreeData& data, CostType type, double costThreshold, bool collapseRecursion) { auto member = memberForType(type); - double totalCost = 0; - foreach (const auto& frame, topDownData) { - totalCost += frame.cost.*member; - } + const auto totalCost = data.resultData->totalCosts().*member; KColorScheme scheme(QPalette::Active); const QPen pen(scheme.foreground().color()); - KFormat format; - QString label; - switch (type) { - case Allocations: - label = i18n("%1 allocations in total", totalCost); - break; - case Temporary: - label = i18n("%1 temporary allocations in total", totalCost); - break; - case Peak: - label = i18n("%1 peak memory consumption", format.formatByteSize(totalCost, 1, KFormat::MetricBinaryDialect)); - break; - case Leaked: - label = i18n("%1 leaked in total", format.formatByteSize(totalCost, 1, KFormat::MetricBinaryDialect)); - break; - } - auto rootItem = new FrameGraphicsItem(totalCost, type, label); + auto rootItem = new FrameGraphicsItem(totalCost, type, {}, data.resultData); rootItem->setBrush(scheme.background()); rootItem->setPen(pen); - toGraphicsItems(topDownData, rootItem, member, totalCost * costThreshold / 100., collapseRecursion); + toGraphicsItems(data.resultData, data.rows, rootItem, member, totalCost * costThreshold / 100., collapseRecursion); return rootItem; } @@ -386,8 +394,7 @@ SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue) SearchResults result; if (searchValue.isEmpty()) { result.matchType = NoSearch; - } else if (item->symbol().symbol.contains(searchValue, Qt::CaseInsensitive) - || item->symbol().binary.contains(searchValue, Qt::CaseInsensitive)) { + } else if (item->match(searchValue)) { result.directCost += item->cost(); result.matchType = DirectMatch; } @@ -408,8 +415,8 @@ SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue) } } -FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) - : QWidget(parent, flags) +FlameGraph::FlameGraph(QWidget* parent) + : QWidget(parent) , m_costSource(new QComboBox(this)) , m_scene(new QGraphicsScene(this)) , m_view(new QGraphicsView(this)) @@ -450,8 +457,15 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) m_view->viewport()->setMouseTracking(true); m_view->setFont(QFont(QStringLiteral("monospace"))); - auto bottomUpCheckbox = new QCheckBox(i18n("Bottom-Down View"), this); - bottomUpCheckbox->setToolTip(i18n("Enable the bottom-down flame graph view. When this is unchecked, " + m_backButton = new QPushButton(this); + m_backButton->setIcon(QIcon::fromTheme(QStringLiteral("go-previous"))); + m_backButton->setToolTip(QStringLiteral("Go back in symbol view history")); + m_forwardButton = new QPushButton(this); + m_forwardButton->setIcon(QIcon::fromTheme(QStringLiteral("go-next"))); + m_forwardButton->setToolTip(QStringLiteral("Go forward in symbol view history")); + + auto bottomUpCheckbox = new QCheckBox(i18n("Bottom-Up View"), this); + bottomUpCheckbox->setToolTip(i18n("Enable the bottom-up flame graph view. When this is unchecked, " "the top-down view is enabled by default.")); bottomUpCheckbox->setChecked(m_showBottomUpData); connect(bottomUpCheckbox, &QCheckBox::toggled, this, [this, bottomUpCheckbox] { @@ -496,6 +510,8 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) auto controls = new QWidget(this); controls->setLayout(new QHBoxLayout); + controls->layout()->addWidget(m_backButton); + controls->layout()->addWidget(m_forwardButton); controls->layout()->addWidget(m_costSource); controls->layout()->addWidget(bottomUpCheckbox); controls->layout()->addWidget(collapseRecursionCheckbox); @@ -511,6 +527,8 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) m_searchResultsLabel->hide(); setLayout(new QVBoxLayout); + layout()->setContentsMargins(0, 0, 0, 0); + layout()->setSpacing(0); layout()->addWidget(controls); layout()->addWidget(m_view); layout()->addWidget(m_displayLabel); @@ -518,8 +536,12 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) m_backAction = KStandardAction::back(this, SLOT(navigateBack()), this); addAction(m_backAction); + connect(m_backButton, &QPushButton::released, m_backAction, &QAction::trigger); + m_forwardAction = KStandardAction::forward(this, SLOT(navigateForward()), this); addAction(m_forwardAction); + connect(m_forwardButton, &QPushButton::released, m_forwardAction, &QAction::trigger); + m_resetAction = new QAction(QIcon::fromTheme(QStringLiteral("go-first")), i18n("Reset View"), this); m_resetAction->setShortcut(Qt::Key_Escape); connect(m_resetAction, &QAction::triggered, this, [this]() { selectItem(0); }); @@ -533,6 +555,10 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags) auto* action = menu->addAction(i18n("View Caller/Callee")); connect(action, &QAction::triggered, this, [this, item]() { emit callerCalleeViewRequested(item->symbol()); }); + + auto* copy = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), tr("Copy")); + connect(copy, &QAction::triggered, this, [item]() { qApp->clipboard()->setText(item->description()); }); + menu->addSeparator(); } menu->addActions(actions()); @@ -621,9 +647,12 @@ void FlameGraph::showData() { setData(nullptr); - m_buildingScene = true; using namespace ThreadWeaver; auto data = m_showBottomUpData ? m_bottomUpData : m_topDownData; + if (!data.resultData) + return; + + m_buildingScene = true; bool collapseRecursion = m_collapseRecursion; auto source = m_costSource->currentData().value(); auto threshold = m_costThreshold; @@ -708,7 +737,8 @@ void FlameGraph::selectItem(FrameGraphicsItem* item) rect.setWidth(rootWidth); parent->setRect(rect); if (parent->parentItem()) { - foreach (auto sibling, parent->parentItem()->childItems()) { + const auto children = parent->parentItem()->childItems(); + for (auto sibling : children) { sibling->setVisible(sibling == parent); } } @@ -736,7 +766,6 @@ void FlameGraph::setSearchValue(const QString& value) m_searchResultsLabel->hide(); } else { QString label; - KFormat format; const auto costFraction = Util::formatCostRelative(match.directCost, m_rootItem->cost()); switch (m_costSource->currentData().value()) { case Allocations: @@ -746,9 +775,8 @@ void FlameGraph::setSearchValue(const QString& value) break; case Peak: case Leaked: - label = i18n("%1 (%2% of total of %3) matched by search.", - format.formatByteSize(match.directCost, 1, KFormat::MetricBinaryDialect), costFraction, - format.formatByteSize(m_rootItem->cost(), 1, KFormat::MetricBinaryDialect)); + label = i18n("%1 (%2% of total of %3) matched by search.", Util::formatBytes(match.directCost), + costFraction, Util::formatBytes(m_rootItem->cost())); break; } m_searchResultsLabel->setText(label); @@ -772,7 +800,13 @@ void FlameGraph::navigateForward() void FlameGraph::updateNavigationActions() { - m_backAction->setEnabled(m_selectedItem > 0); - m_forwardAction->setEnabled(m_selectedItem + 1 < m_selectionHistory.size()); - m_resetAction->setEnabled(m_selectedItem > 0); + const bool hasItems = m_selectedItem > 0; + const bool isNotLastItem = m_selectedItem + 1 < m_selectionHistory.size(); + m_backAction->setEnabled(hasItems); + m_forwardAction->setEnabled(isNotLastItem); + m_resetAction->setEnabled(hasItems); + m_backButton->setEnabled(hasItems); + m_forwardButton->setEnabled(isNotLastItem); } + +#include "moc_flamegraph.cpp" diff --git a/src/analyze/gui/flamegraph.h b/src/analyze/gui/flamegraph.h index 99d01383..580f7dab 100644 --- a/src/analyze/gui/flamegraph.h +++ b/src/analyze/gui/flamegraph.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef FLAMEGRAPH_H #define FLAMEGRAPH_H @@ -29,6 +17,7 @@ class QGraphicsView; class QComboBox; class QLabel; class QLineEdit; +class QPushButton; class FrameGraphicsItem; @@ -36,7 +25,7 @@ class FlameGraph : public QWidget { Q_OBJECT public: - FlameGraph(QWidget* parent = nullptr, Qt::WindowFlags flags = 0); + FlameGraph(QWidget* parent = nullptr); ~FlameGraph(); void setTopDownData(const TreeData& topDownData); @@ -76,11 +65,12 @@ private slots: QAction* m_forwardAction = nullptr; QAction* m_backAction = nullptr; QAction* m_resetAction = nullptr; + QPushButton* m_backButton = nullptr; + QPushButton* m_forwardButton = nullptr; const FrameGraphicsItem* m_tooltipItem = nullptr; FrameGraphicsItem* m_rootItem = nullptr; QVector m_selectionHistory; int m_selectedItem = -1; - int m_minRootWidth = 0; bool m_showBottomUpData = false; bool m_collapseRecursion = true; bool m_buildingScene = false; diff --git a/src/analyze/gui/gui.cpp b/src/analyze/gui/gui.cpp index e8cd0bbc..7197ea1a 100644 --- a/src/analyze/gui/gui.cpp +++ b/src/analyze/gui/gui.cpp @@ -1,45 +1,72 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include #include -#include #include #include +#include + +#include "analyze/suppressions.h" +#include "util/config.h" -#include "mainwindow.h" #include "gui_config.h" +#include "mainwindow.h" +#include "proxystyle.h" + +#include +#include +#include + +// FIXME: patch KIconTheme so that this isn't needed here +void Q_DECL_UNUSED initRCCIconTheme() +{ + const QString iconThemeRcc = qApp->applicationDirPath() + QStringLiteral("/../share/icons/breeze/breeze-icons.rcc"); + if (!QFile::exists(iconThemeRcc)) { + qWarning("cannot find icons rcc: %ls", qUtf16Printable(iconThemeRcc)); + return; + } + + const QString iconThemeName = QStringLiteral("kf5_rcc_theme"); + const QString iconSubdir = QStringLiteral("/icons/") + iconThemeName; + if (!QResource::registerResource(iconThemeRcc, iconSubdir)) { + qWarning("Invalid rcc file: %ls", qUtf16Printable(iconThemeRcc)); + } + + if (!QFile::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) { + qWarning("No index.theme found in %ls", qUtf16Printable(iconThemeRcc)); + QResource::unregisterResource(iconThemeRcc, iconSubdir); + } + + // Tell Qt about the theme + // Note that since qtbase commit a8621a3f8, this means the QPA (i.e. KIconLoader) will NOT be used. + QIcon::setThemeName(iconThemeName); // Qt looks under :/icons automatically + // Tell KIconTheme about the theme, in case KIconLoader is used directly + KIconTheme::forceThemeForTests(iconThemeName); +} int main(int argc, char** argv) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif + QApplication app(argc, argv); + app.setStyle(new ProxyStyle); #if APPIMAGE_BUILD - QIcon::setThemeSearchPaths({app.applicationDirPath() + QLatin1String("/../share/icons/")}); - QIcon::setThemeName(QStringLiteral("breeze")); + initRCCIconTheme(); #endif KLocalizedString::setApplicationDomain("heaptrack"); - KAboutData aboutData(QStringLiteral("heaptrack_gui"), i18n("Heaptrack GUI"), QStringLiteral("0.1"), - i18n("A visualizer for heaptrack data files."), KAboutLicense::LGPL, - i18n("Copyright 2015, Milian Wolff "), QString(), + KAboutData aboutData(QStringLiteral("heaptrack_gui"), i18n("Heaptrack GUI"), + QStringLiteral(HEAPTRACK_VERSION_STRING), i18n("A visualizer for heaptrack data files."), + KAboutLicense::LGPL, i18n("Copyright 2015, Milian Wolff "), QString(), QStringLiteral("mail@milianw.de")); aboutData.addAuthor(i18n("Milian Wolff"), i18n("Original author, maintainer"), QStringLiteral("mail@milianw.de"), @@ -55,27 +82,56 @@ int main(int argc, char** argv) QCommandLineParser parser; aboutData.setupCommandLine(&parser); - QCommandLineOption diffOption{{QStringLiteral("d"), QStringLiteral("diff")}, - i18n("Base profile data to compare other files to."), - QStringLiteral("")}; + QCommandLineOption diffOption {{QStringLiteral("d"), QStringLiteral("diff")}, + i18n("Base profile data to compare other files to."), + QStringLiteral("")}; parser.addOption(diffOption); + QCommandLineOption suppressionsOption { + {QStringLiteral("s"), QStringLiteral("suppressions")}, + i18n("Load list of leak suppressions from the specified file. Specify one suppression per line, and start each " + "line with 'leak:', i.e. use the LSAN suppression file format."), + QStringLiteral("")}; + parser.addOption(suppressionsOption); + QCommandLineOption disableEmbeddedSuppressionsOption { + {QStringLiteral("disable-embedded-suppressions")}, + i18n("Ignore suppression definitions that are embedded into the heaptrack data file. By default, heaptrack " + "will copy the suppressions optionally defined via a `const char *__lsan_default_suppressions()` symbol " + "in the debuggee application. These are then always applied when analyzing the data, unless this feature " + "is explicitly disabled using this command line option.")}; + parser.addOption(disableEmbeddedSuppressionsOption); + QCommandLineOption disableBuiltinSuppressionsOption { + {QStringLiteral("disable-builtin-suppressions")}, + i18n( + "Ignore suppression definitions that are built into heaptrack. By default, heaptrack will suppress certain " + "known leaks in common system libraries.")}; + parser.addOption(disableBuiltinSuppressionsOption); parser.addPositionalArgument(QStringLiteral("files"), i18n("Files to load"), i18n("[FILE...]")); parser.process(app); aboutData.processCommandLine(&parser); - auto createWindow = []() -> MainWindow* { + bool parsedOk = false; + const auto suppressions = parseSuppressions(parser.value(suppressionsOption).toStdString(), &parsedOk); + if (!parsedOk) { + return 1; + } + + auto createWindow = [&]() -> MainWindow* { auto window = new MainWindow; window->setAttribute(Qt::WA_DeleteOnClose); + window->setSuppressions(suppressions); + window->setDisableEmbeddedSuppressions(parser.isSet(disableEmbeddedSuppressionsOption)); + window->setDisableBuiltinSuppressions(parser.isSet(disableBuiltinSuppressionsOption)); window->show(); return window; }; - foreach (const QString& file, parser.positionalArguments()) { + const auto files = parser.positionalArguments(); + for (const auto& file : files) { createWindow()->loadFile(file, parser.value(diffOption)); } - if (parser.positionalArguments().isEmpty()) { + if (files.isEmpty()) { createWindow(); } diff --git a/src/analyze/gui/gui_config.h.cmake b/src/analyze/gui/gui_config.h.cmake index b54258b1..68e27d5d 100644 --- a/src/analyze/gui/gui_config.h.cmake +++ b/src/analyze/gui/gui_config.h.cmake @@ -1,20 +1,8 @@ /* - * Copyright 2017-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2017-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef HEAPTRACK_GUI_CONFIG_H #define HEAPTRACK_GUI_CONFIG_H diff --git a/src/analyze/gui/hashmodel.cpp b/src/analyze/gui/hashmodel.cpp index a02bacfc..f23e4532 100644 --- a/src/analyze/gui/hashmodel.cpp +++ b/src/analyze/gui/hashmodel.cpp @@ -1,28 +1,10 @@ /* - hashmodel.cpp + hashmodel.cpp - This file is part of Hotspot, the Qt GUI for performance analysis. + SPDX-FileCopyrightText: 2016-2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff - Copyright (C) 2016-2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com - Author: Milian Wolff - - Licensees holding valid commercial KDAB Hotspot licenses may use this file in - accordance with Hotspot Commercial License Agreement provided with the Software. - - Contact info@kdab.com if any conditions of this licensing are not clear to you. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . + SPDX-License-Identifier: GPL-2.0-or-later */ #include "hashmodel.h" diff --git a/src/analyze/gui/hashmodel.h b/src/analyze/gui/hashmodel.h index cade9618..931e915e 100644 --- a/src/analyze/gui/hashmodel.h +++ b/src/analyze/gui/hashmodel.h @@ -1,28 +1,10 @@ /* - hashmodel.h + hashmodel.h - This file is part of Hotspot, the Qt GUI for performance analysis. + SPDX-FileCopyrightText: 2016-2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff - Copyright (C) 2016-2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com - Author: Milian Wolff - - Licensees holding valid commercial KDAB Hotspot licenses may use this file in - accordance with Hotspot Commercial License Agreement provided with the Software. - - Contact info@kdab.com if any conditions of this licensing are not clear to you. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . + SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once @@ -31,7 +13,7 @@ #include #include -template +template class HashModel : public QAbstractTableModel { public: diff --git a/src/analyze/gui/heaptrack_app_icon.svg b/src/analyze/gui/heaptrack_app_icon.svg new file mode 100644 index 00000000..d5db1131 --- /dev/null +++ b/src/analyze/gui/heaptrack_app_icon.svg @@ -0,0 +1,1991 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HEAPTRACK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/analyze/gui/histogrammodel.cpp b/src/analyze/gui/histogrammodel.cpp index bc6b7b54..b6850618 100644 --- a/src/analyze/gui/histogrammodel.cpp +++ b/src/analyze/gui/histogrammodel.cpp @@ -1,26 +1,13 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "histogrammodel.h" #include -#include #include #include @@ -29,6 +16,8 @@ #include +#include + namespace { QColor colorForColumn(int column, int columnCount) { @@ -46,8 +35,8 @@ HistogramModel::~HistogramModel() = default; QVariant HistogramModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Vertical && role == Qt::DisplayRole && section >= 0 && section < m_data.size()) { - return m_data.at(section).sizeLabel; + if (orientation == Qt::Vertical && role == Qt::DisplayRole && section >= 0 && section < m_data.rows.size()) { + return m_data.rows.at(section).sizeLabel; } return {}; } @@ -67,14 +56,16 @@ QVariant HistogramModel::data(const QModelIndex& index, int role) const return {}; } - const auto& row = m_data.at(index.row()); + const auto& row = m_data.rows.at(index.row()); const auto& column = row.columns[index.column()]; if (role == Qt::ToolTipRole) { if (index.column() == 0) { return i18n("%1 allocations in total", column.allocations); } - return i18n("%1 allocations from %2 in %3 (%4)", column.allocations, column.symbol.symbol, column.symbol.binary, - column.symbol.path); + return i18n("%1 allocations from %2, totalling %3 allocated with an average of %4 per allocation", + column.allocations, Util::toString(column.symbol, *m_data.resultData, Util::Long), + Util::formatBytes(column.totalAllocated), + Util::formatBytes(column.totalAllocated / column.allocations)); } return column.allocations; } @@ -92,11 +83,12 @@ int HistogramModel::rowCount(const QModelIndex& parent) const if (parent.isValid()) { return 0; } - return m_data.size(); + return m_data.rows.size(); } void HistogramModel::resetData(const HistogramData& data) { + Q_ASSERT(data.resultData); beginResetModel(); m_data = data; endResetModel(); @@ -108,3 +100,5 @@ void HistogramModel::clearData() m_data = {}; endResetModel(); } + +#include "moc_histogrammodel.cpp" diff --git a/src/analyze/gui/histogrammodel.h b/src/analyze/gui/histogrammodel.h index a9c6255e..49b9a4ef 100644 --- a/src/analyze/gui/histogrammodel.h +++ b/src/analyze/gui/histogrammodel.h @@ -1,31 +1,22 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef HISTOGRAMMODEL_H #define HISTOGRAMMODEL_H #include +#include + #include "treemodel.h" struct HistogramColumn { qint64 allocations; + qint64 totalAllocated; Symbol symbol; }; Q_DECLARE_TYPEINFO(HistogramColumn, Q_MOVABLE_TYPE); @@ -34,7 +25,7 @@ struct HistogramRow { HistogramRow() { - columns.fill({0, {}}); + columns.fill({0, 0, {}}); } enum { @@ -47,7 +38,12 @@ struct HistogramRow Q_DECLARE_TYPEINFO(HistogramRow, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(HistogramRow) -using HistogramData = QVector; +struct HistogramData +{ + QVector rows; + std::shared_ptr resultData; +}; +Q_DECLARE_METATYPE(HistogramData) class HistogramModel : public QAbstractTableModel { diff --git a/src/analyze/gui/histogramwidget.cpp b/src/analyze/gui/histogramwidget.cpp index 8f38b43f..e36c341e 100644 --- a/src/analyze/gui/histogramwidget.cpp +++ b/src/analyze/gui/histogramwidget.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "histogramwidget.h" @@ -33,10 +21,10 @@ #include #include -#include #include #include "histogrammodel.h" +#include "util.h" using namespace KChart; @@ -52,8 +40,7 @@ class SizeAxis : public CartesianAxis const QString customizedLabel(const QString& label) const override { - KFormat format(QLocale::system()); - return format.formatByteSize(label.toDouble(), 1, KFormat::MetricBinaryDialect); + return Util::formatBytes(label.toLongLong()); } }; @@ -150,3 +137,5 @@ void HistogramWidget::setModel(QAbstractItemModel* model) } #include "histogramwidget.moc" + +#include "moc_histogramwidget.cpp" diff --git a/src/analyze/gui/histogramwidget.h b/src/analyze/gui/histogramwidget.h index 5818c4fa..ae0af36c 100644 --- a/src/analyze/gui/histogramwidget.h +++ b/src/analyze/gui/histogramwidget.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef HISTOGRAMWIDGET_H #define HISTOGRAMWIDGET_H diff --git a/src/analyze/gui/locationdata.h b/src/analyze/gui/locationdata.h index b4784f83..bfdb41a5 100644 --- a/src/analyze/gui/locationdata.h +++ b/src/analyze/gui/locationdata.h @@ -1,57 +1,33 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef LOCATIONDATA_H #define LOCATIONDATA_H +#include #include -#include -#include +#include #include -#include - -using SymbolId = uint64_t; +Q_DECLARE_METATYPE(ModuleIndex) +Q_DECLARE_METATYPE(FunctionIndex) +Q_DECLARE_METATYPE(FileIndex) struct Symbol { - Symbol(const QString& symbol = {}, const QString& binary = {}, const QString& path = {}, SymbolId symbolId = 0) - : symbol(symbol) - , binary(binary) - , path(path) - , symbolId(symbolId) - { - } - // function name - QString symbol; - // dso / executable name - QString binary; + FunctionIndex functionId; // path to dso / executable - QString path; - // ID - SymbolId symbolId; + ModuleIndex moduleId; bool operator==(const Symbol& rhs) const { - return symbolId == rhs.symbolId; + return functionId == rhs.functionId && moduleId == rhs.moduleId; } bool operator!=(const Symbol& rhs) const @@ -61,26 +37,13 @@ struct Symbol bool operator<(const Symbol& rhs) const { - return symbolId < rhs.symbolId; + return std::tie(functionId, moduleId) < std::tie(rhs.functionId, rhs.moduleId); } bool isValid() const { - return symbolId > 0; + return *this != Symbol {}; } - - struct FullEqual { - bool operator()(const Symbol &lhs, const Symbol &rhs) const { - return lhs.symbol == rhs.symbol && - lhs.binary == rhs.binary && - lhs.path == rhs.path; - } - }; - struct FullLessThan { - bool operator()(const Symbol &lhs, const Symbol &rhs) const { - return std::tie(lhs.symbol, lhs.binary, lhs.path) < std::tie(rhs.symbol, rhs.binary, rhs.path); - } - }; }; Q_DECLARE_TYPEINFO(Symbol, Q_MOVABLE_TYPE); @@ -88,43 +51,43 @@ Q_DECLARE_METATYPE(Symbol) struct FileLine { - QString file; + FileIndex fileId; int line; bool operator==(const FileLine& rhs) const { - return file == rhs.file && line == rhs.line; - } - - bool operator<(const FileLine& rhs) const - { - return std::tie(file, line) < std::tie(rhs.file, rhs.line); - } - - QString toString() const - { - return file.isEmpty() ? QStringLiteral("??") : (file + QLatin1Char(':') + QString::number(line)); + return fileId == rhs.fileId && line == rhs.line; } }; Q_DECLARE_TYPEINFO(FileLine, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(FileLine) -inline QString unresolvedFunctionName() +const QString& unresolvedFunctionName(); + +namespace std { +template <> +struct hash { - static QString msg = i18n(""); - return msg; + std::size_t operator()(const Symbol symbol) const + { + return boost::hash_value(std::tie(symbol.functionId.index, symbol.moduleId.index)); + } +}; } -inline uint qHash(const Symbol& symbol, uint seed_ = 0) +inline uint qHash(const Symbol& symbol, uint seed = 0) { - return qHash(symbol.symbolId, seed_); + QtPrivate::QHashCombine hash; + seed = hash(seed, symbol.functionId); + seed = hash(seed, symbol.moduleId); + return seed; } -inline uint qHash(const FileLine& location, uint seed_ = 0) +inline uint qHash(const FileLine& location, uint seed = 0) { - size_t seed = seed_; - boost::hash_combine(seed, qHash(location.file)); - boost::hash_combine(seed, location.line); + QtPrivate::QHashCombine hash; + seed = hash(seed, location.fileId); + seed = hash(seed, location.line); return seed; } diff --git a/src/analyze/gui/mainwindow.cpp b/src/analyze/gui/mainwindow.cpp index dab78d19..1ebd4c9c 100644 --- a/src/analyze/gui/mainwindow.cpp +++ b/src/analyze/gui/mainwindow.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "mainwindow.h" @@ -24,23 +12,30 @@ #include #include +#include #include +#include #include +#include #include #include #include #include +#include #include +#include #include #include -#include -#include + +#include "analyze/suppressions.h" #include "callercalleemodel.h" #include "costdelegate.h" +#include "costheaderview.h" #include "parser.h" #include "stacksmodel.h" +#include "suppressionsmodel.h" #include "topproxy.h" #include "treemodel.h" #include "treeproxy.h" @@ -72,32 +67,53 @@ const char IDE[] = "IDE"; } } -struct IdeSettings +enum IDE { - const char* const app; - const char* const args; - const char* const name; + KDevelop, + Kate, + KWrite, + GEdit, + GVim, + QtCreator, + LAST_IDE }; +struct IdeSettings +{ + QString app; + QString args; + QString name; -static const IdeSettings ideSettings[] = { - {"kdevelop", "%f:%l:%c", I18N_NOOP("KDevelop")}, - {"kate", "%f --line %l --column %c", I18N_NOOP("Kate")}, - {"kwrite", "%f --line %l --column %c", I18N_NOOP("KWrite")}, - {"gedit", "%f +%l:%c", I18N_NOOP("gedit")}, - {"gvim", "%f +%l", I18N_NOOP("gvim")}, - {"qtcreator", "-client %f:%l", I18N_NOOP("Qt Creator")} + bool isAppAvailable() const + { + return !QStandardPaths::findExecutable(app).isEmpty(); + } }; -static const int ideSettingsSize = sizeof(ideSettings) / sizeof(IdeSettings); -bool isAppAvailable(const char* app) +IdeSettings ideSettings(IDE ide) { - return !QStandardPaths::findExecutable(QString::fromUtf8(app)).isEmpty(); -} + switch (ide) { + case KDevelop: + return {QStringLiteral("kdevelop"), QStringLiteral("%f:%l:%c"), MainWindow::tr("KDevelop")}; + case Kate: + return {QStringLiteral("kate"), QStringLiteral("%f --line %l --column %c"), MainWindow::tr("Kate")}; + case KWrite: + return {QStringLiteral("kwrite"), QStringLiteral("%f --line %l --column %c"), MainWindow::tr("KWrite")}; + case GEdit: + return {QStringLiteral("gedit"), QStringLiteral("%f +%l:%c"), MainWindow::tr("gedit")}; + case GVim: + return {QStringLiteral("gvim"), QStringLiteral("%f +%l"), MainWindow::tr("gvim")}; + case QtCreator: + return {QStringLiteral("qtcreator"), QStringLiteral("-client %f:%l"), MainWindow::tr("Qt Creator")}; + case LAST_IDE: + break; + }; + Q_UNREACHABLE(); +}; int firstAvailableIde() { - for (int i = 0; i < ideSettingsSize; ++i) { - if (isAppAvailable(ideSettings[i].app)) { + for (int i = 0; i < LAST_IDE; ++i) { + if (ideSettings(static_cast(i)).isAppAvailable()) { return i; } } @@ -143,19 +159,29 @@ void addLocationContextMenu(QTreeView* treeView, MainWindow* window) if (!index.isValid()) { return; } + const auto resultData = index.data(SourceMapModel::ResultDataRole).value(); + Q_ASSERT(resultData); const auto location = index.data(SourceMapModel::LocationRole).value(); - if (!QFile::exists(location.file)) { + const auto file = resultData->string(location.fileId); + if (!QFile::exists(file)) { return; } auto menu = new QMenu(treeView); auto openFile = new QAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open file in editor"), menu); - QObject::connect(openFile, &QAction::triggered, openFile, [location, window] { - window->navigateToCode(location.file, location.line); - }); + QObject::connect(openFile, &QAction::triggered, openFile, + [file, line = location.line, window] { window->navigateToCode(file, line); }); menu->addAction(openFile); menu->popup(treeView->mapToGlobal(pos)); }); + QObject::connect(treeView, &QTreeView::activated, window, [window](const QModelIndex& index) { + const auto resultData = index.data(SourceMapModel::ResultDataRole).value(); + Q_ASSERT(resultData); + const auto location = index.data(SourceMapModel::LocationRole).value(); + const auto file = resultData->string(location.fileId); + if (QFile::exists(file)) + window->navigateToCode(file, location.line); + }); } Qt::SortOrder defaultSortOrder(QAbstractItemModel* model, int column) @@ -178,16 +204,17 @@ void setupTopView(TreeModel* source, QTreeView* view, TopProxy::Type type, T cal proxy->setSourceModel(source); proxy->setSortRole(TreeModel::SortRole); view->setModel(proxy); - sortByColumn(view, 0); + sortByColumn(view, 1); view->header()->setStretchLastSection(true); setupTreeContextMenu(view, callback); } #if KChart_FOUND -void addChartTab(QTabWidget* tabWidget, const QString& title, ChartModel::Type type, const Parser* parser, - void (Parser::*dataReady)(const ChartData&), MainWindow* window) +ChartWidget* addChartTab(QTabWidget* tabWidget, const QString& title, ChartModel::Type type, const Parser* parser, + void (Parser::*dataReady)(const ChartData&), MainWindow* window) { auto tab = new ChartWidget(tabWidget->parentWidget()); + QObject::connect(parser, &Parser::summaryAvailable, tab, &ChartWidget::setSummaryData); tabWidget->addTab(tab, title); tabWidget->setTabEnabled(tabWidget->indexOf(tab), false); auto model = new ChartModel(type, tab); @@ -197,6 +224,9 @@ void addChartTab(QTabWidget* tabWidget, const QString& title, ChartModel::Type t tabWidget->setTabEnabled(tabWidget->indexOf(tab), true); }); QObject::connect(window, &MainWindow::clearData, model, &ChartModel::clearData); + QObject::connect(window, &MainWindow::clearData, tab, [tab]() { tab->setSelection({}); }); + QObject::connect(tab, &ChartWidget::filterRequested, window, &MainWindow::reparse); + return tab; } #endif @@ -204,17 +234,17 @@ template void setupTreeModel(TreeModel* model, QTreeView* view, CostDelegate* costDelegate, QLineEdit* filterFunction, QLineEdit* filterModule, T callback) { - auto proxy = new TreeProxy(TreeModel::FunctionColumn, TreeModel::ModuleColumn, model); + auto proxy = new TreeProxy(TreeModel::SymbolRole, TreeModel::ResultDataRole, model); proxy->setSourceModel(model); proxy->setSortRole(TreeModel::SortRole); view->setModel(proxy); + sortByColumn(view, TreeModel::PeakColumn); view->setItemDelegateForColumn(TreeModel::PeakColumn, costDelegate); view->setItemDelegateForColumn(TreeModel::LeakedColumn, costDelegate); view->setItemDelegateForColumn(TreeModel::AllocationsColumn, costDelegate); view->setItemDelegateForColumn(TreeModel::TemporaryColumn, costDelegate); - view->hideColumn(TreeModel::FunctionColumn); - view->hideColumn(TreeModel::ModuleColumn); + view->setHeader(new CostHeaderView(view)); QObject::connect(filterFunction, &QLineEdit::textChanged, proxy, &TreeProxy::setFunctionFilter); QObject::connect(filterModule, &QLineEdit::textChanged, proxy, &TreeProxy::setModuleFilter); @@ -224,7 +254,7 @@ void setupTreeModel(TreeModel* model, QTreeView* view, CostDelegate* costDelegat void setupCallerCallee(CallerCalleeModel* model, QTreeView* view, QLineEdit* filterFunction, QLineEdit* filterModule) { auto costDelegate = new CostDelegate(CallerCalleeModel::SortRole, CallerCalleeModel::TotalCostRole, view); - auto callerCalleeProxy = new TreeProxy(CallerCalleeModel::SymbolColumn, CallerCalleeModel::BinaryColumn, model); + auto callerCalleeProxy = new TreeProxy(CallerCalleeModel::SymbolRole, CallerCalleeModel::ResultDataRole, model); callerCalleeProxy->setSourceModel(model); callerCalleeProxy->setSortRole(CallerCalleeModel::SortRole); view->setModel(callerCalleeProxy); @@ -237,14 +267,13 @@ void setupCallerCallee(CallerCalleeModel* model, QTreeView* view, QLineEdit* fil view->setItemDelegateForColumn(CallerCalleeModel::InclusiveLeakedColumn, costDelegate); view->setItemDelegateForColumn(CallerCalleeModel::InclusiveAllocationsColumn, costDelegate); view->setItemDelegateForColumn(CallerCalleeModel::InclusiveTemporaryColumn, costDelegate); - view->hideColumn(CallerCalleeModel::SymbolColumn); - view->hideColumn(CallerCalleeModel::BinaryColumn); + view->setHeader(new CostHeaderView(view)); QObject::connect(filterFunction, &QLineEdit::textChanged, callerCalleeProxy, &TreeProxy::setFunctionFilter); QObject::connect(filterModule, &QLineEdit::textChanged, callerCalleeProxy, &TreeProxy::setModuleFilter); } template -Model* setupModelAndProxyForView(QTreeView* view, int nonCostColumns) +Model* setupModelAndProxyForView(QTreeView* view) { auto model = new Model(view); auto proxy = new QSortFilterProxyModel(model); @@ -252,18 +281,13 @@ Model* setupModelAndProxyForView(QTreeView* view, int nonCostColumns) proxy->setSortRole(Model::SortRole); view->setModel(proxy); sortByColumn(view, Model::InitialSortColumn); - view->header()->setStretchLastSection(false); - view->header()->setSectionResizeMode(0, QHeaderView::Stretch); - for (int i = 0; i < nonCostColumns; ++i) { - if (i != Model::LocationColumn) { - view->hideColumn(i); - } - } auto costDelegate = new CostDelegate(Model::SortRole, Model::TotalCostRole, view); - for (int i = nonCostColumns; i < Model::NUM_COLUMNS; ++i) { + for (int i = 1; i < Model::NUM_COLUMNS; ++i) { view->setItemDelegateForColumn(i, costDelegate); } + view->setHeader(new CostHeaderView(view)); + return model; } @@ -300,7 +324,8 @@ MainWindow::MainWindow(QWidget* parent) m_ui->pages->setCurrentWidget(m_ui->openPage); // TODO: proper progress report m_ui->loadingProgress->setMinimum(0); - m_ui->loadingProgress->setMaximum(0); + m_ui->loadingProgress->setMaximum(1000); // range is set as 0 to 1000 for fractional % bar display + m_ui->loadingProgress->setValue(0); auto bottomUpModel = new TreeModel(this); auto topDownModel = new TreeModel(this); @@ -314,6 +339,22 @@ MainWindow::MainWindow(QWidget* parent) m_ui->tabWidget->setTabEnabled(m_ui->tabWidget->indexOf(m_ui->topDownTab), false); m_ui->tabWidget->setTabEnabled(m_ui->tabWidget->indexOf(m_ui->flameGraphTab), false); + auto* suppressionsModel = new SuppressionsModel(this); + { + auto* proxy = new QSortFilterProxyModel(this); + proxy->setSourceModel(suppressionsModel); + m_ui->suppressionsView->setModel(proxy); + auto* delegate = new CostDelegate(SuppressionsModel::SortRole, SuppressionsModel::TotalCostRole, this); + m_ui->suppressionsView->setItemDelegateForColumn(static_cast(SuppressionsModel::Columns::Leaked), + delegate); + m_ui->suppressionsView->setItemDelegateForColumn(static_cast(SuppressionsModel::Columns::Matches), + delegate); + + auto margins = m_ui->suppressionBox->contentsMargins(); + margins.setLeft(0); + m_ui->suppressionBox->setContentsMargins(margins); + } + connect(m_parser, &Parser::bottomUpDataAvailable, this, [=](const TreeData& data) { bottomUpModel->resetData(data); if (!m_diffMode) { @@ -340,12 +381,12 @@ MainWindow::MainWindow(QWidget* parent) connect(m_parser, &Parser::summaryAvailable, this, [=](const SummaryData& data) { bottomUpModel->setSummary(data); topDownModel->setSummary(data); - KFormat format; + suppressionsModel->setSuppressions(data); + m_ui->suppressionBox->setVisible(suppressionsModel->rowCount() > 0); + const auto isFiltered = data.filterParameters.isFilteredByTime(data.totalTime); QString textLeft; QString textCenter; QString textRight; - const double totalTimeS = 0.001 * data.totalTime; - const double peakTimeS = 0.001 * data.peakTime; { QTextStream stream(&textLeft); const auto debuggee = insertWordWrapMarkers(data.debuggee); @@ -355,15 +396,21 @@ MainWindow::MainWindow(QWidget* parent) debuggee) : i18n("

debuggee:
%1
", - debuggee)) - // xgettext:no-c-format - << i18n("
total runtime:
%1s
", totalTimeS) - << i18n("
total system memory:
%1
", - format.formatByteSize(data.totalSystemMemory, 1, KFormat::MetricBinaryDialect)) + debuggee)); + if (isFiltered) { + stream << i18n("
total runtime:
%1, filtered from %2 to %3 (%4)
", + Util::formatTime(data.totalTime), Util::formatTime(data.filterParameters.minTime), + Util::formatTime(data.filterParameters.maxTime), + Util::formatTime(data.filterParameters.maxTime - data.filterParameters.minTime)); + } else { + stream << i18n("
total runtime:
%1
", Util::formatTime(data.totalTime)); + } + stream << i18n("
total system memory:
%1
", Util::formatBytes(data.totalSystemMemory)) << "
"; } { QTextStream stream(&textCenter); + const double totalTimeS = 0.001 * (data.filterParameters.maxTime - data.filterParameters.minTime); stream << "
" << i18n("
calls to allocation functions:
%1 " "(%2/s)
", @@ -379,14 +426,24 @@ MainWindow::MainWindow(QWidget* parent) QTextStream stream(&textRight); stream << "
" << i18n("
peak heap memory consumption:
%1 " - "after %2s
", - format.formatByteSize(data.cost.peak, 1, KFormat::MetricBinaryDialect), peakTimeS) + "after %2", + Util::formatBytes(data.cost.peak), Util::formatTime(data.peakTime)) << i18n("
peak RSS (including heaptrack " "overhead):
%1
", - format.formatByteSize(data.peakRSS, 1, KFormat::MetricBinaryDialect)) - << i18n("
total memory leaked:
%1
", - format.formatByteSize(data.cost.leaked, 1, KFormat::MetricBinaryDialect)) - << "
"; + Util::formatBytes(data.peakRSS)); + if (isFiltered) { + stream << i18n("
memory consumption delta:
%1
", + Util::formatBytes(data.cost.leaked)); + } else { + if (data.totalLeakedSuppressed) { + stream << i18n("
total memory leaked:
%1 (%2 suppressed)
", + Util::formatBytes(data.cost.leaked), Util::formatBytes(data.totalLeakedSuppressed)); + } else { + stream << i18n("
total memory leaked:
%1
", + Util::formatBytes(data.cost.leaked)); + } + } + stream << "
"; } m_ui->summaryLeft->setText(textLeft); @@ -395,6 +452,7 @@ MainWindow::MainWindow(QWidget* parent) m_ui->tabWidget->setTabEnabled(m_ui->tabWidget->indexOf(m_ui->summaryTab), true); }); connect(m_parser, &Parser::progressMessageAvailable, m_ui->progressLabel, &QLabel::setText); + connect(m_parser, &Parser::progress, m_ui->loadingProgress, &QProgressBar::setValue); auto removeProgress = [this] { auto layout = qobject_cast(m_ui->loadingPage->layout()); Q_ASSERT(layout); @@ -414,12 +472,20 @@ MainWindow::MainWindow(QWidget* parent) m_ui->messages->hide(); #if KChart_FOUND - addChartTab(m_ui->tabWidget, i18n("Consumed"), ChartModel::Consumed, m_parser, &Parser::consumedChartDataAvailable, - this); - addChartTab(m_ui->tabWidget, i18n("Allocations"), ChartModel::Allocations, m_parser, - &Parser::allocationsChartDataAvailable, this); - addChartTab(m_ui->tabWidget, i18n("Temporary Allocations"), ChartModel::Temporary, m_parser, - &Parser::temporaryChartDataAvailable, this); + auto consumedTab = addChartTab(m_ui->tabWidget, i18n("Consumed"), ChartModel::Consumed, m_parser, + &Parser::consumedChartDataAvailable, this); + auto allocationsTab = addChartTab(m_ui->tabWidget, i18n("Allocations"), ChartModel::Allocations, m_parser, + &Parser::allocationsChartDataAvailable, this); + auto temporaryAllocationsTab = addChartTab(m_ui->tabWidget, i18n("Temporary Allocations"), ChartModel::Temporary, + m_parser, &Parser::temporaryChartDataAvailable, this); + auto syncSelection = [=](const ChartWidget::Range& selection) { + consumedTab->setSelection(selection); + allocationsTab->setSelection(selection); + temporaryAllocationsTab->setSelection(selection); + }; + connect(consumedTab, &ChartWidget::selectionChanged, syncSelection); + connect(allocationsTab, &ChartWidget::selectionChanged, syncSelection); + connect(temporaryAllocationsTab, &ChartWidget::selectionChanged, syncSelection); auto sizesTab = new HistogramWidget(this); m_ui->tabWidget->addTab(sizesTab, i18n("Sizes")); @@ -434,18 +500,19 @@ MainWindow::MainWindow(QWidget* parent) }); #endif - auto calleesModel = setupModelAndProxyForView(m_ui->calleeView, 2); - auto callersModel = setupModelAndProxyForView(m_ui->callerView, 2); - auto sourceMapModel = setupModelAndProxyForView(m_ui->locationView, 1); + auto calleesModel = setupModelAndProxyForView(m_ui->calleeView); + auto callersModel = setupModelAndProxyForView(m_ui->callerView); + auto sourceMapModel = setupModelAndProxyForView(m_ui->locationView); - auto selectCallerCaleeeIndex = [calleesModel, callersModel, sourceMapModel, this](const QModelIndex& index) { - const auto costs = index.data(CallerCalleeModel::TotalCostsRole).value(); + auto selectCallerCaleeeIndex = [callerCalleeModel, calleesModel, callersModel, sourceMapModel, + this](const QModelIndex& index) { + const auto resultData = callerCalleeModel->results().resultData; const auto callees = index.data(CallerCalleeModel::CalleesRole).value(); - calleesModel->setResults(callees, costs); + calleesModel->setResults(callees, resultData); const auto callers = index.data(CallerCalleeModel::CallersRole).value(); - callersModel->setResults(callers, costs); + callersModel->setResults(callers, resultData); const auto sourceMap = index.data(CallerCalleeModel::SourceMapRole).value(); - sourceMapModel->setResults(sourceMap, costs); + sourceMapModel->setResults(sourceMap, resultData); if (index.model() != m_ui->callerCalleeResults->model()) { m_ui->callerCalleeResults->setCurrentIndex( qobject_cast(m_ui->callerCalleeResults->model())->mapFromSource(index)); @@ -496,19 +563,39 @@ MainWindow::MainWindow(QWidget* parent) return false; }; + const QString heaptrackFileFilter = QStringLiteral("heaptrack.*.*.gz heaptrack.*.*.zst"); +#if KIO_VERSION >= QT_VERSION_CHECK(5, 108, 0) + const QStringList heaptrackFileFilters = {heaptrackFileFilter}; + m_ui->openFile->setNameFilters(heaptrackFileFilters); + m_ui->compareTo->setNameFilters(heaptrackFileFilters); +#else + m_ui->openFile->setFilter(heaptrackFileFilter); + m_ui->compareTo->setFilter(heaptrackFileFilter); +#endif + auto validateInput = [this, validateInputFile]() { m_ui->messages->hide(); m_ui->buttonBox->setEnabled(validateInputFile(m_ui->openFile->url().toLocalFile(), false) - && validateInputFile(m_ui->compareTo->url().toLocalFile(), true)); + && validateInputFile(m_ui->compareTo->url().toLocalFile(), true) + && validateInputFile(m_ui->suppressions->url().toLocalFile(), true)); }; connect(m_ui->openFile, &KUrlRequester::textChanged, this, validateInput); connect(m_ui->compareTo, &KUrlRequester::textChanged, this, validateInput); + connect(m_ui->suppressions, &KUrlRequester::textChanged, this, validateInput); connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, [this]() { const auto path = m_ui->openFile->url().toLocalFile(); Q_ASSERT(!path.isEmpty()); const auto base = m_ui->compareTo->url().toLocalFile(); - loadFile(path, base); + + bool parsedOk = false; + m_lastFilterParameters.suppressions = + parseSuppressions(m_ui->suppressions->url().toLocalFile().toStdString(), &parsedOk); + if (parsedOk) { + loadFile(path, base); + } else { + showError(i18n("Failed to parse suppression file.")); + } }); setupStacks(); @@ -550,7 +637,35 @@ MainWindow::MainWindow(QWidget* parent) } }); + m_disableEmbeddedSuppressions = m_ui->menu_Settings->addAction(i18n("Disable Embedded Suppressions")); + m_disableEmbeddedSuppressions->setToolTip( + i18n("Ignore suppression definitions that are embedded into the heaptrack data file. By default, heaptrack " + "will copy the suppressions optionally defined via a `const char *__lsan_default_suppressions()` symbol " + "in the debuggee application. These are then always applied when analyzing the data, unless this feature " + "is explicitly disabled using this command line option.")); + m_disableEmbeddedSuppressions->setCheckable(true); + connect(m_disableEmbeddedSuppressions, &QAction::toggled, this, [this]() { + m_lastFilterParameters.disableEmbeddedSuppressions = m_disableEmbeddedSuppressions->isChecked(); + reparse(m_lastFilterParameters.minTime, m_lastFilterParameters.maxTime); + }); + + m_disableBuiltinSuppressions = m_ui->menu_Settings->addAction(i18n("Disable Builtin Suppressions")); + m_disableBuiltinSuppressions->setToolTip(i18n( + "Ignore suppression definitions that are built into heaptrack. By default, heaptrack will suppress certain " + "known leaks from common system libraries.")); + m_disableBuiltinSuppressions->setCheckable(true); + connect(m_disableBuiltinSuppressions, &QAction::toggled, this, [this]() { + m_lastFilterParameters.disableBuiltinSuppressions = m_disableBuiltinSuppressions->isChecked(); + reparse(m_lastFilterParameters.minTime, m_lastFilterParameters.maxTime); + }); + setupCodeNavigationMenu(); + + m_ui->actionResetFilter->setEnabled(false); + connect(m_ui->actionResetFilter, &QAction::triggered, this, + [this]() { reparse(0, std::numeric_limits::max()); }); + QObject::connect(m_parser, &Parser::finished, this, + [this]() { m_ui->actionResetFilter->setEnabled(m_parser->isFiltered()); }); } MainWindow::~MainWindow() @@ -574,7 +689,22 @@ void MainWindow::loadFile(const QString& file, const QString& diffBase) m_diffMode = true; } m_ui->pages->setCurrentWidget(m_ui->loadingPage); - m_parser->parse(file, diffBase); + m_parser->parse(file, diffBase, m_lastFilterParameters); +} + +void MainWindow::reparse(int64_t minTime, int64_t maxTime) +{ + if (m_ui->pages->currentWidget() != m_ui->resultsPage) { + return; + } + + m_closeAction->setEnabled(false); + m_ui->flameGraphTab->clearData(); + m_ui->loadingLabel->setText(i18n("Reparsing file, please wait...")); + m_ui->pages->setCurrentWidget(m_ui->loadingPage); + m_lastFilterParameters.minTime = minTime; + m_lastFilterParameters.maxTime = maxTime; + m_parser->reparse(m_lastFilterParameters); } void MainWindow::openNewFile() @@ -582,6 +712,8 @@ void MainWindow::openNewFile() auto window = new MainWindow; window->setAttribute(Qt::WA_DeleteOnClose, true); window->show(); + window->setDisableEmbeddedSuppressions(m_lastFilterParameters.disableEmbeddedSuppressions); + window->setSuppressions(m_lastFilterParameters.suppressions); } void MainWindow::closeFile() @@ -647,7 +779,6 @@ void MainWindow::setupStacks() m_ui->stacksDock->setVisible(false); } - void MainWindow::setupCodeNavigationMenu() { // Code Navigation @@ -660,10 +791,11 @@ void MainWindow::setupCodeNavigationMenu() const auto settings = m_config->group(Config::Groups::CodeNavigation); const auto currentIdx = settings.readEntry(Config::Entries::IDE, firstAvailableIde()); - for (int i = 0; i < ideSettingsSize; ++i) { + for (int i = 0; i < LAST_IDE; ++i) { auto action = new QAction(menu); - action->setText(i18n(ideSettings[i].name)); - auto icon = QIcon::fromTheme(QString::fromUtf8(ideSettings[i].app)); + auto ide = ideSettings(static_cast(i)); + action->setText(ide.name); + auto icon = QIcon::fromTheme(ide.app); if (icon.isNull()) { icon = QIcon::fromTheme(QStringLiteral("application-x-executable")); } @@ -671,9 +803,7 @@ void MainWindow::setupCodeNavigationMenu() action->setCheckable(true); action->setChecked(currentIdx == i); action->setData(i); -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // It's not worth it to reimplement missing findExecutable for Qt4. - action->setEnabled(isAppAvailable(ideSettings[i].app)); -#endif + action->setEnabled(ide.isAppAvailable()); group->addAction(action); menu->addAction(action); } @@ -714,7 +844,7 @@ void MainWindow::setCodeNavigationIDE(QAction* action) const auto customCmd = QInputDialog::getText(this, i18n("Custom Code Navigation"), i18n("Specify command to use for code navigation, '%f' will be replaced by the file " - "name, '%l' by the line number and '%c' by the column number."), + "name, '%l' by the line number and '%c' by the column number."), QLineEdit::Normal, settings.readEntry(Config::Entries::CustomCommand)); if (!customCmd.isEmpty()) { settings.writeEntry(Config::Entries::CustomCommand, customCmd); @@ -733,8 +863,9 @@ void MainWindow::navigateToCode(const QString& filePath, int lineNumber, int col const auto ideIdx = settings.readEntry(Config::Entries::IDE, firstAvailableIde()); QString command; - if (ideIdx >= 0 && ideIdx < ideSettingsSize) { - command = QString::fromUtf8(ideSettings[ideIdx].app) + QLatin1Char(' ') + QString::fromUtf8(ideSettings[ideIdx].args); + if (ideIdx >= 0 && ideIdx < LAST_IDE) { + auto ide = ideSettings(static_cast(ideIdx)); + command = ide.app + QLatin1Char(' ') + ide.args; } else if (ideIdx == -1) { command = settings.readEntry(Config::Entries::CustomCommand); } @@ -744,8 +875,26 @@ void MainWindow::navigateToCode(const QString& filePath, int lineNumber, int col command.replace(QStringLiteral("%l"), QString::number(std::max(1, lineNumber))); command.replace(QStringLiteral("%c"), QString::number(std::max(1, columnNumber))); - QProcess::startDetached(command); + auto splitted = KShell::splitArgs(command); + QProcess::startDetached(splitted.takeFirst(), splitted); } else { QDesktopServices::openUrl(QUrl::fromLocalFile(filePath)); } } + +void MainWindow::setDisableEmbeddedSuppressions(bool disable) +{ + m_disableEmbeddedSuppressions->setChecked(disable); +} + +void MainWindow::setDisableBuiltinSuppressions(bool disable) +{ + m_disableBuiltinSuppressions->setChecked(disable); +} + +void MainWindow::setSuppressions(std::vector suppressions) +{ + m_lastFilterParameters.suppressions = std::move(suppressions); +} + +#include "moc_mainwindow.cpp" diff --git a/src/analyze/gui/mainwindow.h b/src/analyze/gui/mainwindow.h index a773f8a3..860a4cdf 100644 --- a/src/analyze/gui/mainwindow.h +++ b/src/analyze/gui/mainwindow.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef MAINWINDOW_H #define MAINWINDOW_H @@ -23,6 +11,8 @@ #include +#include + namespace Ui { class MainWindow; } @@ -30,6 +20,7 @@ class MainWindow; class TreeModel; class ChartModel; class Parser; +class ResultData; class MainWindow : public QMainWindow { @@ -40,12 +31,17 @@ class MainWindow : public QMainWindow public slots: void loadFile(const QString& path, const QString& diffBase = {}); + void reparse(int64_t minTime, int64_t maxTime); void openNewFile(); void closeFile(); void setCodeNavigationIDE(QAction* action); void navigateToCode(const QString& url, int lineNumber, int columnNumber = -1); + void setDisableEmbeddedSuppressions(bool disable); + void setDisableBuiltinSuppressions(bool disable); + void setSuppressions(std::vector suppressions); + signals: void clearData(); @@ -63,6 +59,9 @@ public slots: QAction* m_openNewAction = nullptr; QAction* m_closeAction = nullptr; QAction* m_quitAction = nullptr; + QAction* m_disableEmbeddedSuppressions = nullptr; + QAction* m_disableBuiltinSuppressions = nullptr; + FilterParameters m_lastFilterParameters; }; #endif // MAINWINDOW_H diff --git a/src/analyze/gui/mainwindow.ui b/src/analyze/gui/mainwindow.ui index fd11d682..53ffc960 100644 --- a/src/analyze/gui/mainwindow.ui +++ b/src/analyze/gui/mainwindow.ui @@ -13,6 +13,9 @@ MainWindow + + Path to a file containing leak suppression rules in the LSAN format. + @@ -33,8 +36,7 @@ KMessageWidget::Information - - .. + @@ -69,9 +71,6 @@ <p>Or, alternatively, you can attach to a running process via</p> <pre><code>heaptrack --pid $(pidof &lt;yourapplication&gt;)</code></pre></qt>
- - heaptrack.*.*.gz heaptrack.*.*.zst - path/to/heaptrack.$APP.$PID.{gz,zst} @@ -85,9 +84,6 @@ <qt>You can optionally specify a second heaptrack data file to compare to. If set, this file will be used as a base and its cost gets subtracted from the primary data costs.</qt> - - heaptrack.*.*.gz heaptrack.*.*.zst - path/to/heaptrack.$APP.$PID.{gz,zst} @@ -116,6 +112,26 @@ + + + + Path to a file containing leak suppression rules in the LSAN format. + + + Suppressions: + + + suppressions + + + + + + + path/to/lsan_suppressions.txt + + + @@ -221,7 +237,7 @@ - 2 + 0 @@ -298,6 +314,15 @@ + + 0 + + + 0 + + + 0 + @@ -305,6 +330,9 @@ + + 0 + @@ -422,6 +450,9 @@ + + 0 + @@ -464,6 +495,37 @@ + + + + Suppressions + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + false + + + + + + @@ -811,21 +873,42 @@ Setti&ngs + + + Filter + + + + + + + + + + Reset Filter + + - - KMessageWidget - QFrame -
kmessagewidget.h
-
KUrlRequester QWidget
kurlrequester.h
+ + KCollapsibleGroupBox + QWidget +
kcollapsiblegroupbox.h
+ 1 +
+ + KMessageWidget + QFrame +
kmessagewidget.h
+
FlameGraph QWidget diff --git a/src/analyze/gui/org.kde.heaptrack.appdata.xml b/src/analyze/gui/org.kde.heaptrack.appdata.xml index acd45955..a6643d1e 100644 --- a/src/analyze/gui/org.kde.heaptrack.appdata.xml +++ b/src/analyze/gui/org.kde.heaptrack.appdata.xml @@ -2,7 +2,7 @@ org.kde.heaptrack.desktop CC0-1.0 - GPL-2.0+ + GPL-2.0-or-later Heaptrack Heaptrack Heaptrack @@ -10,11 +10,15 @@ Heaptrack Heaptrack Heaptrack + Heaptrack Heaptrack + Heaptrack Heaptrack Heaptrack + Heaptrack Heaptrack Heaptrack + Heaptrack 힙 추적 Heaptrack Heaptrack @@ -23,20 +27,26 @@ Heaptrack Heaptrack Heaptrack + Heaptrack Heaptrack Heaptrack Heaptrack xxHeaptrackxx 堆栈追踪 A heap memory profiler for Linux - Un perfilador de memòria en monticles per al Linux - Un perfilador de memòria en monticles per al Linux + Un analitzador del rendiment de la memòria en monticles per al Linux + Un analitzador del rendiment de la memòria en monticles per a Linux En heap-hukommelsesprofilering til Linux A heap memory profiler for Linux + Staplomemora profililo por Linukso Un analizador de rendimiento de la memoria de almacenamiento libre para Linux + Linux-erako memoria dinamikoaren («heap») profilatzaile bat + Un analyseur de mémoire dynamique pour Linux Un analizador de uso de memoria dinámica (heap) para Linux + Un profilator de memoria heap per Linux Sebuah profil memori tumpukan untuk Linux Un profiler della memoria heap per Linux + დროებითი მეხსიერების პროფაილერი Linux-სთვის 리눅스 힙 추적 메모리 프로파일러 Een profiler van heap-geheugen voor Linux Profileringsprogram for heap-minne @@ -44,61 +54,72 @@ Um analisador da memória de dados para o Linux Um analisador de performance de memória de dados para o Linux Profiler pamäťovej haldy pre Linux + Analizator profila pomnilnika kopice za Linux Ett heap-profileringsverktyg för Linux - Linux için yığın bellek profili - Засіб профілювання «купи» пам’яті для Linux + Linux için yığın bellek profilleyici + Засіб профілювання «купи» пам'яті для Linux xxA heap memory profiler for Linuxxx 用于 Linux 的堆内存分析器

Heaptrack traces all memory allocations and annotates these events with stack traces. Dedicated analysis tools then allow you to interpret the heap memory profile to:

-

El «heaptrack» rastreja totes les assignacions de memòria i anota aquests esdeveniments amb seguiments de pila. Les eines d'anàlisi dedicades que hi ha a continuació, us permetran interpretar el perfil de memòria en monticles:

-

El «heaptrack» rastreja totes les assignacions de memòria i anota aquests esdeveniments amb seguiments de pila. Les eines d'anàlisi dedicades que hi ha a continuació, vos permetran interpretar el perfil de memòria en monticles:

+

El «heaptrack» rastreja totes les assignacions de memòria i anota aquests esdeveniments amb seguiments de pila. Les eines d'anàlisi dedicades que hi ha a continuació, us permetran interpretar l'anàlisi de rendiment de la memòria en monticles:

+

«heaptrack» rastreja totes les assignacions de memòria i anota estos esdeveniments amb seguiments de pila. Les eines d'anàlisi dedicades que hi ha a continuació, vos permetran interpretar l'anàlisi de rendiment de la memòria en monticles:

Heaptrack sporer alle hukommelsesallokeringer og anmærker begivenhederne med stakspor. Dedikerede analyseværktøjer som giver dig mulighed for at fortolke heapens hukommelsesprofil til:

Heaptrack traces all memory allocations and annotates these events with stack traces. Dedicated analysis tools then allow you to interpret the heap memory profile to:

+

Heaptrack spuras ĉiujn memorajn atribuojn kaj notas ĉi tiujn eventojn per stakspuroj. Dediĉitaj analiziloj tiam permesas vin interpreti la staplomemoran profilon al:

Heaptrack rastrea todas las asignaciones de memoria y anota estos eventos con trazas de la pila para poder usar herramientas de dedicadas que le permitan interpretar el análisis de rendimiento de la memoria de almacenamiento libre para:

+

Le logiciel « Heaptrack » permet le suivi des allocations de mémoire. Il annote les demandes par des traces dans la pile. Des outils dédiés d'analyse vous permettent ensuite d'interpréter le profil de la mémoire dynamique pour :

Heaptrack fai un seguimento de todas as asociacións de memoria e apunta os eventos co historial da rima. Logo pode usar ferramentas de análise para interpretar os datos de uso da memoria dinámica (heap) para:

Heaptrack melacak semua alokasi memori dan membubuhi keterangan peristiwa ini dengan jejak tumpukan. Alat analisis khusus kemudian memungkinkan kamu untuk menginterpretasikan profil memori tumpukan untuk:

Heaptrack traccia tutte le allocazioni di memoria e le annota con tracciati dello stack. Degli strumenti dedicati di analisi ti permettono quindi di interpretare il profilo della memoria heap in modo da:

힙 추적은 모든 메모리 할당을 추적하고 스택 추적과 메모리 할당을 연결합니다. 분석 도구를 사용하여 힙 메모리 프로필을 해석할 수 있습니다:

-

Heaptrack traceert alle toewijzigingen van geheugen en annoteert deze gebeurtenissen met stacktraces. Specifieke hulpmiddelen voor analyse bieden u de mogelijkheid om het geheugenprofiel van de heap te interpreteren:

+

Heaptrack traceert alle toewijzingen van geheugen en annoteert deze gebeurtenissen met stacktraces. Specifieke hulpmiddelen voor analyse bieden u de mogelijkheid om het geheugenprofiel van de heap te interpreteren:

Heaptrack sporar alle minnereserveringar og merkjer dei med tilhøyrande stabelspor. Analyseverktøyet lèt deg så tolka minneprofilen for å:

Heaptrack rejestruje wszystkie przydziały pamięci i przypisuje tym zdarzeniom ślady stosu. Dedykowane narzędzia analizy, które umożliwiają interpretację profilu pamięcy aby:

O Heaptrack faz uma análise de todas as alocações de memória e anota esses eventos com os registos de chamadas. As ferramentas de análise dedicadas permitem-lhe então interpretar o perfil da memória de dados para:

O heaptrack traça todas as alocações de memória e anota estes eventos com rastreios de pilha. As ferramentas dedicadas de análises permitirão a você interpretar o perfil de memória da pilha para:

Heaptrack trasuje všetky pamäťové alokácie a anotuje tieto udalosti s trasovaním sledu. Samostatné analytické nástroje vám pomôžu interpretovať profil pamäťovej haldy na:

+

Heaptrack zasleduje vse dodelitve pomnilnika in jim pripisuje dogodke v sklad sledi. Namenska orodja za analizo vam nato omogočajo razlago profila kopice pomnilnika:

Heaptrack spårar alla minnestilldelningar och förser händelserna med noter om bakåtspårningar av stacken. Särskilda analysverktyg låter dig sedan tolka heap-minnesprofilen för att:

-

Heaptrack, tüm bellek tahsislerini izler ve bu olayları yığın izleriyle açıklar. Ayrılmış analiz araçları daha sonra yığın bellek profilini yorumlamanıza izin verir:

-

Heaptrack трасує усі запити щодо розміщення даних у пам’яті і анотує ці події за допомогою трасування стека. Далі, спеціалізовані інструменти для аналізу надають вам змогу обробляти дані профілювання пам’яті з такою метою:

+

Heaptrack, tüm bellek ayırmalarını izler ve bu olayları yığın izleriyle açıklar. Özel çözümleme araçları, daha sonra yığın bellek profilini yorumlamanıza izin verir:

+

Heaptrack трасує усі запити щодо розміщення даних у пам'яті і анотує ці події за допомогою трасування стека. Далі, спеціалізовані інструменти для аналізу надають вам змогу обробляти дані профілювання пам'яті з такою метою:

xxHeaptrack traces all memory allocations and annotates these events with stack traces. Dedicated analysis tools then allow you to interpret the heap memory profile to:xx

+

Heaptrack跟踪所有内存分配,并使用堆栈跟踪注释这些事件。专用的分析工具允许你解释堆内存配置文件:

  • find hotspots that need to be optimized to reduce the memory footprint of your application
  • -
  • troba els punts d'accés que necessiten optimitzar-se per a reduir el consum de memòria de la vostra aplicació
  • -
  • troba els punts d'accés que necessiten optimitzar-se per a reduir el consum de memòria de la vostra aplicació
  • +
  • troba els punts crítics que necessiten optimitzar-se per a reduir el consum de memòria de la vostra aplicació
  • +
  • troba els punts crítics que necessiten optimitzar-se per a reduir el consum de memòria de la vostra aplicació
  • find hotspots som behøver optimering for at reducere dit programs hukommelsesfodaftryk
  • find hotspots that need to be optimized to reduce the memory footprint of your application
  • +
  • trovi retpunktojn, kiuj bezonas esti optimumigitaj por redukti la memorspuron de via aplikaĵo
  • encontrar cuellos de botella que es necesario optimizar para reducir el impacto de su aplicación en la memoria
  • +
  • trouver les zones principales de code à améliorer pour réduire l'empreinte mémoire de votre application
  • Atopar puntos quentes que cómpre optimizar para reducir o consumo de memoria da aplicación
  • menemukan hotspot yang perlu dioptimalkan untuk mengurangi jejak memori aplikasimu
  • trovare gli «hotspot» che devono essere ottimizzati per ridurre il consumo di memoria della tua applicazione
  • -
  • 프로그램의 메모리 사용량을 줄일 때 필요한 핫스팟(최적화해야 할 지점) 확인
  • +
  • 앱의 메모리 사용량을 줄일 때 필요한 핫스팟(최적화해야 할 지점) 확인
  • zoek hotspots die het nodig hebben om geoptimaliseerd te worden om de voetafdruk van het geheugen van uw toepassing te verminderen
  • Finna problemområde som må optimerast for å redusera minnebruken til programmet.
  • znaleźć gorące miejsca, które wymagają optymalizacji do zmniejszenia zapotrzebowania na pamięć dla twojej aplikacji
  • descobrir pontos críticos que precisam de optimização para reduzir a 'pegada' de memória da sua aplicação
  • encontrar pontos de acesso que precisam ser otimizados para reduzir o consumo de memória de seu aplicativo
  • nájdenie hotspotu, ktoý treba optimalizovať na zníženie použitia pamäte vašej aplikácie
  • +
  • poišče vroče točke, ki jih je treba optimizirati, da zmanjšate pomnilniški odtis vašega programa
  • Hitta överbelastningsställen som behöver optimeras för att reducera programmets minnesanvändning.
  • -
  • uygulamanızın belleğin kapladığı alanı azaltmak için optimize edilmesi gereken etkin noktaları bulun
  • -
  • Виявлення проблемних місць, які має бути оптимізовано з метою зменшення споживання пам’яті вашою програмою.
  • +
  • uygulamanızın kapladığı belleği azaltmak için eniyilenmesi gereken etkin noktaları bulun
  • +
  • Виявлення проблемних місць, які має бути оптимізовано з метою зменшення споживання пам'яті вашою програмою.
  • xxfind hotspots that need to be optimized to reduce the memory footprint of your applicationxx
  • +
  • 寻找需要优化的热点,以减少应用程序的内存占用
  • find memory leaks, i.e. locations that allocate memory which is never deallocated
  • troba les fuites de memòria, és a dir, llocs que assignen memòria que mai es desassignarà
  • troba les fuites de memòria, és a dir, llocs que assignen memòria que mai es desassignarà
  • find hukommelseslæk, dvs. positioner som allokerer hukommelse som aldrig deallokeres
  • find memory leaks, i.e. locations that allocate memory which is never deallocated
  • +
  • trovi memorlikojn, t.e. lokojn kiuj asignas memoron kiu neniam estas deasignita
  • encontrar fugas de memoria (es decir, lugares donde se asigna memoria que no se llega a liberar)
  • +
  • trouver les fuites de mémoires, c'est-à-dire, des parties de logiciels, qui s'allouent de la mémoire mais qui ne la libèrent jamais
  • Atopar perdas de memoria, é dicir, lugares que asignan memoria que nunca se libera.
  • menemukan kebocoran memori, misal lokasi yang mengalokasikan memori yang tidak pernah dialokasikan
  • trovare i buchi di memoria, cioè le posizioni dove è allocata memoria che non viene mai rilasciata
  • @@ -109,16 +130,20 @@
  • descobrir fugas de memória, i.e. localizações que alocam memória que nunca é libertada
  • encontrar vazamentos de memória, por exemplo localizações que alocam memória que nunca é desalocada
  • nájdenie pamäťových únikov, teda miest, ktoré alokujú pamäť, ktorá sa nikdy neuvoľní
  • +
  • poiščite puščanje pomnilnika, to so lokacije, ki dodelijo pomnilnik, ki pa ga nikoli ne sprostijo
  • Hitta minnesläckor, dvs. ställen där minne tilldelas som aldrig frigörs.
  • -
  • bellek sızıntılarını, yani hiçbir zaman tahsis edilmemiş belleği tahsis eden yerleri bulun
  • -
  • Виявлення витоків пам’яті, тобто розміщень даних у пам’яті без відповідних вивільнень, коли дані стають непотрібними.
  • +
  • bellek sızıntılarını, yani hiçbir zaman tahsis edilmemiş belleği ayıran yerleri bulun
  • +
  • Виявлення витоків пам'яті, тобто розміщень даних у пам'яті без відповідних вивільнень, коли дані стають непотрібними.
  • xxfind memory leaks, i.e. locations that allocate memory which is never deallocatedxx
  • +
  • 查找内存泄漏,即分配内存的位置永远不会被释放
  • find allocation hotspots, i.e. code locations that trigger a lot of memory allocation calls
  • -
  • troba els punts d'accés d'assignació, és a dir, les ubicacions al codi que desencadenen un munt de crides d'assignació de memòria
  • -
  • troba els punts d'accés d'assignació, és a dir, les ubicacions al codi que desencadenen un munt de crides d'assignació de memòria
  • +
  • troba els punts crítics d'assignació, és a dir, les ubicacions al codi que desencadenen un munt de crides d'assignació de memòria
  • +
  • troba els punts crítics d'assignació, és a dir, les ubicacions al codi que desencadenen un munt de crides d'assignació de memòria
  • find allokerede hotspots, dvs. kodepositioner som udløser en masse kald for hukommelsesallokering
  • find allocation hotspots, i.e. code locations that trigger a lot of memory allocation calls
  • +
  • trovi atribuajn retpunktojn, t.e. kodlokojn, kiuj ekigas multajn memorajn alvokojn
  • encontrar cuellos de botella de asignaciones (es decir, lugares del código fuente que desencadenan numerosas llamadas de asignación de memoria)
  • +
  • trouver les zones principales de code faisant des allocations mémoire, c'est-à-dire celles faisant de nombreuses requêtes d'allocation mémoire
  • Atopar puntos quentes de asignación, é dicir, lugares do código que causan moitas chamadas de asignación de memoria.
  • menemukan hotspot alokasi, misal lokasi kode yang memicu banyak panggilan alokasi memori
  • trovare gli «hotspot» delle allocazioni, cioè posizioni nel codice che producono molte chiamate di allocazione della memoria
  • @@ -129,19 +154,23 @@
  • descobrir pontos críticos de alocação, i.e. localizações de memória que despoletam bastantes chamadas de alocação de memória
  • encontrar pontos de acesso de alocação, por exemplo localização de códigos que ativam muitas chamadas de alocação de memória
  • nájdenie hotspotov alokácií, teda iest, ktoré spúšťajú veľa volaní alokácie pamäte
  • +
  • poiščite vroče točke dodeljevanja, to so lokacije kod, ki sprožijo veliko klicev po dodeljevanju pomnilnika
  • Hitta överbelastningsställen för tilldelningar, dvs. ställen i koden som orsakar många anrop till minnestilldelning.
  • -
  • tahsis edilen noktaları, yani bir çok bellek ayırma çağrısını tetikleyen kod yerlerini bulun
  • -
  • Виявлення проблемних місць розміщення, тобто місць у програмному коді, які призводять до багатьох викликів щодо розміщення у пам’яті.
  • +
  • ayrılan noktaları, demeli bir çok bellek ayırma çağrısını tetikleyen kod yerlerini bulun
  • +
  • Виявлення проблемних місць розміщення, тобто місць у програмному коді, які призводять до багатьох викликів щодо розміщення у пам'яті.
  • xxfind allocation hotspots, i.e. code locations that trigger a lot of memory allocation callsxx
  • +
  • 找到分配热点,即触发大量内存分配调用的代码位置
  • find temporary allocations, which are allocations that are directly followed by their deallocation
  • troba les assignacions temporals, són les assignacions que són seguides directament per la cancel·lació de la seva assignació
  • troba les assignacions temporals, són les assignacions que són seguides directament per la cancel·lació de la seua assignació
  • find midlertidige allokeringer, som er allokeringer der direkte følges af deres deallokering
  • find temporary allocations, which are allocations that are directly followed by their deallocation
  • +
  • trovi provizorajn asignojn, kiuj estas asignoj, kiuj estas rekte sekvataj de sia malasignado
  • encontrar asignaciones de memoria temporales, que son asignaciones que son inmediatamente seguidas por sus correspondientes liberaciones
  • +
  • trouver les allocations transitoires, c'est-à-dire enchaînant une allocation suivie directement par une désallocation.
  • Atopar asignacións temporais, asignacións que se liberan no momento.
  • menemukan alokasi sementara, yaitu alokasi yang langsung diikuti oleh alokasi mereka
  • -
  • trovare allocazioni temporanee, cioè allocazioni che sono seguite direttamente dalle rispettivi de-allocazioni
  • +
  • trovare allocazioni temporanee, cioè allocazioni che sono seguite direttamente dalle rispettive de-allocazioni
  • 메모리 할당 다음에 바로 해제가 나오는 임시 할당 확인
  • zoek naar tijdelijke toewijzingen, die toewijzingen zijn die direct gevolgd worden door hun vrijgave
  • Finna «mellombelse» reserveringar – reserveringar som umiddelbart vert etterfølgde av avreserveringar.
  • @@ -149,10 +178,12 @@
  • descobrir alocações temporárias, que são alocações que são directamente seguidas da sua libertação
  • encontrar alocações temporárias, que são alocações que são seguidas diretamente por sua desalocação
  • nájdenie dočasných alokácií, čo sú alokácie, ktoré priamo nasleduje ich dealokácia
  • +
  • poiščite začasne dodelitve pomnilnika, ki jim neposredno sledijo njihove sprostitve
  • Hitta tillfälliga tilldelningar, som är tilldelningar som direkt frigörs.
  • -
  • tahsisin ardından bırakılacak olan, geçici tahsisleri bulun
  • -
  • Виявлення тимчасових розміщень, тобто розміщень даних у пам’яті, за якими одразу ж слідують вивільнення відповідних ділянок пам’яті.
  • +
  • ayırmanın ardından bırakılacak olan, geçici ayırmaları bulun
  • +
  • Виявлення тимчасових розміщень, тобто розміщень даних у пам'яті, за якими одразу ж слідують вивільнення відповідних ділянок пам'яті.
  • xxfind temporary allocations, which are allocations that are directly followed by their deallocationxx
  • +
  • 查找临时分配,即直接在其释放之后进行的分配
https://phabricator.kde.org/dashboard/view/28/ @@ -161,72 +192,79 @@ https://cdn.kde.org/screenshots/heaptrack/gui_summary.png - Summary of tracked heap memory allocation data. - Resum del seguiment de les dades d'assignació de la memòria en monticles. - Resum del seguiment de les dades d'assignació de la memòria en monticles. - Opsummering af sporet allokeringsdata for heap-hukommelse. - Summary of tracked heap memory allocation data. - Sumario de datos de asignación de memoria de almacenamiento libre rastreada. + Summary of tracked heap memory allocation data + Resum del seguiment de les dades d'assignació de la memòria en monticles + Resum del seguiment de les dades d'assignació de la memòria en monticles + Summary of tracked heap memory allocation data + Resumo de spuritaj amasomemoraj asignodatenoj + Sumario de datos de asignación de memoria de almacenamiento libre rastreada + Résumé des données d'allocation pour la mémoire dynamique surveillée. Resumo dos datos de asignación de memoria dinámica (heap) da que se fai seguimento. - Ringkasan data alokasi memori tumpukan yang terlacak. - Riepilogo dei dati delle allocazioni di memoria heap tracciati. - 추적된 힙 메모리 할당 데이터 요약을 봅니다. - Samenvatting van gevolgde gegevens voor heap-geheugen toewijzen. - Samandrag av minnereserveringsdata. - podsumować dane przydzielone w pamięci - Um resumo dos dados de alocação de memória registados. - Resumo dos dados rastreados de alocação de memória de dados. - Sumár alokačných údajov sledovanej pamäťovej haldy. + Ringkasan data alokasi memori tumpukan yang terlacak + Riepilogo dei dati delle allocazioni di memoria heap tracciati + 추적된 힙 메모리 할당 데이터 요약 + Samenvatting van gevolgde gegevens voor heap-geheugen toewijzen + Samandrag av minnereserveringsdata + Podsumować śledzonych danych przydzielonych na pamięci stosu + Um resumo dos dados de alocação de memória de dados registados + Resumo dos dados rastreados de alocação de memória de dados + Povzetek podatkov o dodelitvi pomnilnika v kopici Sammanfattning av spårad heap-minnestilldelningsdata - İzlenen yığın bellek tahsis verilerinin özeti. - Резюме щодо стеження за розміщенням даних у «купі» пам’яті. - xxSummary of tracked heap memory allocation data.xx + İzlenen yığın bellek ayırma verisinin özeti + Резюме щодо стеження за розміщенням даних у «купі» пам'яті + xxSummary of tracked heap memory allocation dataxx + 跟踪的堆内存分配数据摘要 https://cdn.kde.org/screenshots/heaptrack/gui_flamegraph.png - Flamegraph visualization of number of heap memory allocations. - Visualització del gràfic de flames del nombre d'assignacions de memòria en monticles. - Visualització del gràfic de flames del nombre d'assignacions de memòria en monticles. - Flammegraf-visualisering af antallet af allokeringer for heap-hukommelse. - Flamegraph visualisation of number of heap memory allocations. - Visualización de gráfico de llamas del número de asignaciones de memoria de almacenamiento libre. + Flamegraph visualization of number of heap memory allocations + Visualització del gràfic de flames del nombre d'assignacions de memòria en monticles + Visualització del gràfic de flames del nombre d'assignacions de memòria en monticles + Flamegraph visualisation of number of heap memory allocations + Flamgrafea bildigo de nombro da amasmemor-asignoj + Visualización de gráfico de llamas del número de asignaciones de memoria de almacenamiento libre + Affichage graphe en chandelles du nombre d'allocations de mémoire dynamique. Visualización mediante un gráfico de chamas do número de asignacións de memoria dinámica (heap). - Visualisasi Flamegraph dari jumlah alokasi memori tumpukan. - Visualizzazione di tipo Flamegraph del totale di allocazioni di memoria heap. - 힙 메모리 할당 횟수를 플레임 그래프로 봅니다. - Flamegraph visualisatie van het aantal toewijzingen van heap-geheugen. - Flammegraf-visualisering av talet på minnereserveringar. - zobrazować na wykresie płomieni przydzielnia pamięci. - Uma visualização em mapa de calor das alocações de memória de dados. - Visualização em gráfico de chamas do número de alocações de memória de dados. - Plameňový graf vizualizácie počtu alokácií pamätovej hromady. - Visualisering av antal heap-minnestilldelningar med Flamegraph. - Yığın bellek tahis etme sayısının Flamegraph görüntüsü. - Інтерактивна гістограма кількості розміщень у «купі» пам’яті. - xxFlamegraph visualization of number of heap memory allocations.xx + Visualisasi Flamegraph dari jumlah alokasi memori tumpukan + Visualizzazione di tipo Flamegraph del totale di allocazioni di memoria heap + 힙 메모리 할당 횟수를 플레임 그래프로 보기 + Flamegraph visualisatie van het aantal toewijzingen van heap-geheugen + Flammegraf-visualisering av talet på minnereserveringar + Zobrazowanie liczby przydzieleń pamięci na stosie na wykresie płomieni + Uma visualização em mapa de calor das alocações de memória de dados + Visualização em gráfico de chamas do número de alocações de memória de dados + Grafična vizualizacija števila dodelitev pomnilnika v kopici + Visualisering av antal heap-minnestilldelningar med Flamegraph + Yığın bellek ayırma sayısının Flamegraph görselleştirmesi + Інтерактивна гістограма кількості розміщень у «купі» пам'яті + xxFlamegraph visualization of number of heap memory allocationsxx + 堆内存分配次数的火焰图可视化 https://cdn.kde.org/screenshots/heaptrack/gui_allocations_chart.png - Chart of heap memory allocations over time. - Gràfic de les assignacions de memòria en monticles al llarg del temps. - Gràfic de les assignacions de memòria en monticles al llarg del temps. - Skema af heap-hukommelsesallokeringer over tid. - Chart of heap memory allocations over time. - Gráfico de asignaciones de memoria del almacenamiento libre a lo largo del tiempo. + Chart of heap memory allocations over time + Gràfic de les assignacions de memòria en monticles al llarg del temps + Gràfic de les assignacions de memòria en monticles al llarg del temps + Chart of heap memory allocations over time + Diagramo de amasmemor-asignoj laŭlonge de la tempo + Gráfico de asignaciones de memoria del almacenamiento libre a lo largo del tiempo + Denboran zehar, memoria dinamikoaren esleipenaren diagrama + Graphique des allocations de mémoire dynamique en temps réel Gráfica das asignacións de memoria dinámica (heap) co paso do tempo. - Bagan alokasi memori tumpukan dari waktu ke waktu. - Grafico delle allocazioni della memoria heap nel tempo. - 시간별 힙 메모리 할당 횟수를 그래프로 봅니다. - Grafiek van toewijzingen van heap-geheugen in de tijd. - Diagram over minnereserveringar over tid. - zobrazować przydzielenia pamięci w czasie. - Gráfico das alocações de memória de dados ao longo do tempo. - Gráfico das alocações de memória de dado no período de tempo. - Graf alokácií pamäťovej hromady v čase. - Diagram över heap-minnestilldelningar över tiden. - Zaman için yığın bellek tahsislerinin grafiği. - Діаграма розміщення даних у «купі» пам’яті за часом. - xxChart of heap memory allocations over time.xx + Bagan alokasi memori tumpukan dari waktu ke waktu + Grafico delle allocazioni della memoria heap nel tempo + 시간별 힙 메모리 할당 횟수를 그래프로 보기 + Grafiek van toewijzingen van heap-geheugen in de tijd + Diagram over minnereserveringar over tid + Wykres przydzieleń pamięci na stosie na osi czasu + Gráfico das alocações de memória de dados ao longo do tempo + Gráfico das alocações de memória de dado no período de tempo + Tabela dodelitev pomnilnika za kopico skozi čas + Diagram över heap-minnestilldelningar över tiden + Zaman içinde yığın bellek ayırmalarının grafiği + Діаграма розміщення даних у «купі» пам'яті за часом + xxChart of heap memory allocations over timexx + 随时间推移的堆内存分配图表 KDE @@ -235,4 +273,9 @@ heaptrack_gui heaptrack_print + + + + +
diff --git a/src/analyze/gui/org.kde.heaptrack.desktop b/src/analyze/gui/org.kde.heaptrack.desktop index bb997e6c..4d863098 100644 --- a/src/analyze/gui/org.kde.heaptrack.desktop +++ b/src/analyze/gui/org.kde.heaptrack.desktop @@ -16,11 +16,15 @@ Name[cs]=Heaptrack Name[da]=Heaptrack Name[de]=Heaptrack Name[en_GB]=Heaptrack +Name[eo]=Heaptrack Name[es]=Heaptrack Name[et]=Heaptrack +Name[eu]=Heaptrack Name[fr]=Heaptrack Name[gl]=Heaptrack +Name[ia]=Heaptrack Name[it]=Heaptrack +Name[ka]=Heaptrack Name[ko]=힙 추적 Name[nl]=Heaptrack Name[nn]=Heaptrack @@ -29,23 +33,28 @@ Name[pt]=Heaptrack Name[pt_BR]=Heaptrack Name[ru]=Heaptrack Name[sk]=Heaptrack +Name[sl]=Heaptrack Name[sv]=Heaptrack Name[tr]=Heaptrack Name[uk]=Heaptrack Name[x-test]=xxHeaptrackxx Name[zh_CN]=Heaptrack GenericName=Profiler Frontend -GenericName[ca]=Frontal de l'analitzador del rendiment -GenericName[ca@valencia]=Frontal de l'analitzador del rendiment +GenericName[ca]=Frontal de l'analitzador de rendiment +GenericName[ca@valencia]=Frontal de l'analitzador de rendiment GenericName[cs]=Rozhraní pro profilaci GenericName[da]=Profilerings-frontend GenericName[de]=Profiler-Oberfläche GenericName[en_GB]=Profiler Frontend +GenericName[eo]=Profilila Fasado GenericName[es]=Interfaz de analizador de rendimiento GenericName[et]=Profileerimise kasutajaliides +GenericName[eu]=Profilatzaileren aurrealdekoa GenericName[fr]=Interface de profilage GenericName[gl]=Interface de analizador de rendemento +GenericName[ia]=Fronte de profilator GenericName[it]=Interfaccia a profiler +GenericName[ka]=პროფაილერის წინაბოლო GenericName[ko]=프로파일러 프론트엔드 GenericName[nl]=Frontend van profiler GenericName[nn]=Grensesnitt for profilvising @@ -54,8 +63,9 @@ GenericName[pt]=Interface de Análise de Performance GenericName[pt_BR]=Interface de análise de performance GenericName[ru]=Интерфейс к профилировщику GenericName[sk]=Rozhranie pre profiláciu +GenericName[sl]=Začelje analizatorja profila GenericName[sv]=Profileringsgränssnitt -GenericName[tr]=Profil Önyüzü +GenericName[tr]=Profilci Ön Yüzü GenericName[uk]=Інтерфейс профілювання GenericName[x-test]=xxProfiler Frontendxx GenericName[zh_CN]=分析器前端 @@ -66,11 +76,15 @@ Comment[cs]=Vizualizace dat profilování paměti Comment[da]=Visualisering af data fra hukommelsesprofilering Comment[de]=Visualisierung von Daten des Speicherverhaltens eines Programms Comment[en_GB]=Visualisation of Memory Profiling Data +Comment[eo]=Bildigo de Memorprofilaj Datenoj Comment[es]=Visualización de datos de análisis de rendimiento de la memoria Comment[et]=Mälu profileerimise andmete visualiseerimine +Comment[eu]=Memoria profilatzeko datuak irudikatzea Comment[fr]=Visualisation des données de profilage de la mémoire Comment[gl]=Visualización dos datos da análise de rendemento +Comment[ia]=Visualisation de datos de profilar de memoria Comment[it]=Visualizzazione dei dati di profiling della memoria +Comment[ka]=მეხსიერების პროფილირების მონაცემების ვიზუალიზაცია Comment[ko]=메모리 프로파일링 데이터 시각화 Comment[nl]=Visualisatie van geheugenprofileringsgegevens Comment[nn]=Visualisering av minneprofildata @@ -79,6 +93,7 @@ Comment[pt]=Visualização dos Dados de Performance da Memória Comment[pt_BR]=Visualização de dados de análise da memória Comment[ru]=Визуализация данных потребления памяти Comment[sk]=Vizualizácia dát profilovania pamäte +Comment[sl]=Vizualizacija podatkov za profiliranje pomnilnika Comment[sv]=Visualisering av profileringsdata för minne Comment[tr]=Bellek Profilleme Verisinin Görselleştirilmesi Comment[uk]=Візуалізація даних профілювання пам’яті diff --git a/src/analyze/gui/parser.cpp b/src/analyze/gui/parser.cpp index 87423cf1..a5867c83 100644 --- a/src/analyze/gui/parser.cpp +++ b/src/analyze/gui/parser.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "parser.h" @@ -22,111 +10,61 @@ #include #include +#include +#include #include "analyze/accumulatedtracedata.h" #include #include +#include #include -#include -using namespace std; +#define TSL_NO_EXCEPTIONS 1 +#include +#include + +#include -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) namespace std { template <> -struct hash +struct hash> { - std::size_t operator()(const QString &v) const noexcept + std::size_t operator()(const std::pair& pair) const { - return qHash(v); + return boost::hash_value(std::tie(pair.first.functionId.index, pair.first.moduleId.index, + pair.second.functionId.index, pair.second.moduleId.index)); } }; } -#endif -// Only use this hash when filling in the cache -struct CacheSymbolHash -{ - std::size_t operator()(const Symbol &symbol) const noexcept - { - size_t seed = 0; - boost::hash_combine(seed, std::hash{}(symbol.symbol)); - boost::hash_combine(seed, std::hash{}(symbol.binary)); - boost::hash_combine(seed, std::hash{}(symbol.path)); - return seed; - } -}; +using namespace std; namespace { +Symbol symbol(const Frame& frame, ModuleIndex moduleIndex) +{ + return {frame.functionIndex, moduleIndex}; +} + +Symbol symbol(const InstructionPointer& ip) +{ + return symbol(ip.frame, ip.moduleIndex); +} struct Location { Symbol symbol; FileLine fileLine; }; - -struct StringCache +Location frameLocation(const Frame& frame, ModuleIndex moduleIndex) { - QString func(const Frame& frame) const - { - if (frame.functionIndex) { - // TODO: support removal of template arguments - return stringify(frame.functionIndex); - } else { - return unresolvedFunctionName(); - } - } - - QString file(const Frame& frame) const - { - return stringify(frame.fileIndex); - } - - QString stringify(const StringIndex index) const - { - if (!index || index.index > m_strings.size()) { - return {}; - } else { - return m_strings.at(index.index - 1); - } - } - - Location location(const InstructionPointer& ip) const - { - return frameLocation(ip.frame, ip.moduleIndex); - } - - Location frameLocation(const Frame& frame, const ModuleIndex& moduleIndex) const - { - const auto module = stringify(moduleIndex); - auto binaryIt = m_pathToBinaries.find(module); - if (binaryIt == m_pathToBinaries.end()) { - binaryIt = m_pathToBinaries.insert(module, Util::basename(module)); - } - const SymbolId id = ++m_nextSymbolId; - auto symbol = Symbol{func(frame), *binaryIt, module, id}; - // Insert symbol into the hash, or use existing one (in which case the new ID won't be used) - const auto it = m_symbols.emplace(std::make_pair(std::move(symbol), id)).first; - return {it->first, {file(frame), frame.line}}; - } - - void update(const vector& strings) - { - transform(strings.begin() + m_strings.size(), strings.end(), back_inserter(m_strings), - [](const string& str) { return QString::fromStdString(str); }); - } - - vector m_strings; - // interned module basenames - mutable QHash m_pathToBinaries; - // existing symbols - mutable std::unordered_map m_symbols; - - bool diffMode = false; + return {symbol(frame, moduleIndex), {frame.fileIndex, frame.line}}; +} - mutable SymbolId m_nextSymbolId = 0; -}; +Location location(const InstructionPointer& ip) +{ + return frameLocation(ip.frame, ip.moduleIndex); +} struct ChartMergeData { @@ -142,33 +80,44 @@ struct ChartMergeData const uint64_t MAX_CHART_DATAPOINTS = 500; // TODO: make this configurable via the GUI -struct ParserData final : public AccumulatedTraceData +QVector toQt(const std::vector& suppressions) { - ParserData() - { - } + QVector ret(suppressions.size()); + std::copy(suppressions.begin(), suppressions.end(), ret.begin()); + return ret; +} +} - void updateStringCache() +struct ParserData final : public AccumulatedTraceData +{ + using TimestampCallback = std::function; + ParserData(TimestampCallback timestampCallback) + : timestampCallback(std::move(timestampCallback)) { - stringCache.update(strings); } - void prepareBuildCharts() + void prepareBuildCharts(const std::shared_ptr& resultData) { - if (stringCache.diffMode) { + if (diffMode) { return; } + consumedChartData.resultData = resultData; consumedChartData.rows.reserve(MAX_CHART_DATAPOINTS); + allocationsChartData.resultData = resultData; allocationsChartData.rows.reserve(MAX_CHART_DATAPOINTS); + temporaryChartData.resultData = resultData; temporaryChartData.rows.reserve(MAX_CHART_DATAPOINTS); // start off with null data at the origin - consumedChartData.rows.push_back({}); - allocationsChartData.rows.push_back({}); - temporaryChartData.rows.push_back({}); + lastTimeStamp = filterParameters.minTime; + ChartRows origin; + origin.timeStamp = lastTimeStamp; + consumedChartData.rows.push_back(origin); + allocationsChartData.rows.push_back(origin); + temporaryChartData.rows.push_back(origin); // index 0 indicates the total row - consumedChartData.labels[0] = i18n("total"); - allocationsChartData.labels[0] = i18n("total"); - temporaryChartData.labels[0] = i18n("total"); + consumedChartData.labels[0] = {}; + allocationsChartData.labels[0] = {}; + temporaryChartData.labels[0] = {}; buildCharts = true; maxConsumedSinceLastTimeStamp = 0; @@ -188,33 +137,55 @@ struct ParserData final : public AccumulatedTraceData } // find the top hot spots for the individual data members and remember their // IP and store the label + tsl::robin_map ipToLabelIds; auto findTopChartEntries = [&](qint64 ChartMergeData::*member, int LabelIds::*label, ChartData* data) { - sort(merged.begin(), merged.end(), - [=](const ChartMergeData& left, const ChartMergeData& right) { return left.*member > right.*member; }); - for (size_t i = 0; i < min(size_t(ChartRows::MAX_NUM_COST - 1), merged.size()); ++i) { + sort(merged.begin(), merged.end(), [=](const ChartMergeData& left, const ChartMergeData& right) { + return std::abs(left.*member) > std::abs(right.*member); + }); + for (size_t i = 0; i < min(size_t(ChartRows::MAX_NUM_COST - 2), merged.size()); ++i) { const auto& alloc = merged[i]; if (!(alloc.*member)) { break; } - const auto ip = alloc.ip; - (labelIds[ip].*label) = i + 1; - const auto function = stringCache.func(findIp(ip).frame); - data->labels[i + 1] = function; + (ipToLabelIds[alloc.ip].*label) = i + 1; + data->labels[i + 1] = symbol(findIp(alloc.ip)); + Q_ASSERT(data->labels.size() < ChartRows::MAX_NUM_COST); } }; + ipToLabelIds.reserve(3 * ChartRows::MAX_NUM_COST); findTopChartEntries(&ChartMergeData::consumed, &LabelIds::consumed, &consumedChartData); findTopChartEntries(&ChartMergeData::allocations, &LabelIds::allocations, &allocationsChartData); findTopChartEntries(&ChartMergeData::temporary, &LabelIds::temporary, &temporaryChartData); + + // now iterate the allocations once to build the list of allocations + // we need to look at when we are building the charts in handleTimeStamp + // instead of doing this lookup every time we are handling a time stamp + for (uint32_t i = 0, c = allocations.size(); i < c; ++i) { + const auto ip = findTrace(allocations[i].traceIndex).ipIndex; + auto it = ipToLabelIds.find(ip); + if (it == ipToLabelIds.end()) + continue; + auto ids = it->second; + ids.allocationIndex.index = i; + labelIds.push_back(ids); + } } - void handleTimeStamp(int64_t /*oldStamp*/, int64_t newStamp) override + void handleTimeStamp(int64_t /*oldStamp*/, int64_t newStamp, bool isFinalTimeStamp, ParsePass pass) override { - if (!buildCharts || stringCache.diffMode) { + if (timestampCallback) { + timestampCallback(*this); + } + if (pass == ParsePass::FirstPass) { + return; + } + if (!buildCharts || diffMode) { return; } maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, totalCost.leaked); - const int64_t diffBetweenTimeStamps = totalTime / MAX_CHART_DATAPOINTS; - if (newStamp != totalTime && newStamp - lastTimeStamp < diffBetweenTimeStamps) { + const auto timeSpan = (filterParameters.maxTime - filterParameters.minTime); + const int64_t diffBetweenTimeStamps = timeSpan / MAX_CHART_DATAPOINTS; + if (!isFinalTimeStamp && (newStamp - lastTimeStamp) < diffBetweenTimeStamps) { return; } const auto nowConsumed = maxConsumedSinceLastTimeStamp; @@ -222,35 +193,29 @@ struct ParserData final : public AccumulatedTraceData lastTimeStamp = newStamp; // create the rows - auto createRow = [](int64_t timeStamp, int64_t totalCost) { + auto createRow = [newStamp](int64_t totalCost) { ChartRows row; - row.timeStamp = timeStamp; + row.timeStamp = newStamp; row.cost[0] = totalCost; return row; }; - auto consumed = createRow(newStamp, nowConsumed); - auto allocs = createRow(newStamp, totalCost.allocations); - auto temporary = createRow(newStamp, totalCost.temporary); + auto consumed = createRow(nowConsumed); + auto allocs = createRow(totalCost.allocations); + auto temporary = createRow(totalCost.temporary); // if the cost is non-zero and the ip corresponds to a hotspot function - // selected in the labels, - // we add the cost to the rows column + // selected in the labels, we add the cost to the rows column auto addDataToRow = [](int64_t cost, int labelId, ChartRows* rows) { if (!cost || labelId == -1) { return; } rows->cost[labelId] += cost; }; - for (const auto& alloc : allocations) { - const auto ip = findTrace(alloc.traceIndex).ipIndex; - auto it = labelIds.constFind(ip); - if (it == labelIds.constEnd()) { - continue; - } - const auto& labelIds = *it; - addDataToRow(alloc.leaked, labelIds.consumed, &consumed); - addDataToRow(alloc.allocations, labelIds.allocations, &allocs); - addDataToRow(alloc.temporary, labelIds.temporary, &temporary); + for (const auto& ids : labelIds) { + const auto alloc = allocations[ids.allocationIndex.index]; + addDataToRow(alloc.leaked, ids.consumed, &consumed); + addDataToRow(alloc.allocations, ids.allocations, &allocs); + addDataToRow(alloc.temporary, ids.temporary, &temporary); } // add the rows for this time stamp consumedChartData.rows << consumed; @@ -274,6 +239,29 @@ struct ParserData final : public AccumulatedTraceData debuggee = command; } + void clearForReparse() + { + // data moved to size histogram + { + // we have to reset the allocation count + for (auto& info : allocationInfoCounter) + info.allocations = 0; + // and restore the order to allow fast direct access + std::sort(allocationInfoCounter.begin(), allocationInfoCounter.end(), + [](const ParserData::CountedAllocationInfo& lhs, const ParserData::CountedAllocationInfo& rhs) { + return lhs.info.allocationIndex < rhs.info.allocationIndex; + }); + } + // data moved to chart models + consumedChartData = {}; + allocationsChartData = {}; + temporaryChartData = {}; + labelIds.clear(); + maxConsumedSinceLastTimeStamp = 0; + lastTimeStamp = 0; + buildCharts = false; + } + string debuggee; struct CountedAllocationInfo @@ -285,6 +273,8 @@ struct ParserData final : public AccumulatedTraceData return tie(info.size, allocations) < tie(rhs.info.size, rhs.allocations); } }; + /// counts how often a given allocation info is encountered based on its index + /// used to build the size histogram vector allocationInfoCounter; ChartData consumedChartData; @@ -296,19 +286,25 @@ struct ParserData final : public AccumulatedTraceData // in a per-ChartData hash. struct LabelIds { + AllocationIndex allocationIndex; int consumed = -1; int allocations = -1; int temporary = -1; }; - QHash labelIds; + vector labelIds; int64_t maxConsumedSinceLastTimeStamp = 0; int64_t lastTimeStamp = 0; - StringCache stringCache; - bool buildCharts = false; + bool diffMode = false; + + TimestampCallback timestampCallback; + QElapsedTimer parseTimer; + + QVector qtStrings; }; +namespace { void setParents(QVector& children, const RowData* parent) { children.squeeze(); @@ -318,30 +314,35 @@ void setParents(QVector& children, const RowData* parent) } } -void addCallerCalleeEvent(const Location& location, const AllocationData& cost, QSet* recursionGuard, +void addCallerCalleeEvent(const Location& location, const AllocationData& cost, tsl::robin_set* recursionGuard, CallerCalleeResults* callerCalleeResult) { - auto recursionIt = recursionGuard->find(location.symbol); - if (recursionIt == recursionGuard->end()) { - auto& entry = callerCalleeResult->entry(location.symbol); - auto& locationCost = entry.source(location.fileLine); - - locationCost.inclusiveCost += cost; - if (recursionGuard->isEmpty()) { - // increment self cost for leaf - locationCost.selfCost += cost; - } - recursionGuard->insert(location.symbol); + const auto isLeaf = recursionGuard->empty(); + if (!recursionGuard->insert(location.symbol).second) { + return; + } + + auto& entry = callerCalleeResult->entries[location.symbol]; + auto& locationCost = entry.sourceMap[location.fileLine]; + + locationCost.inclusiveCost += cost; + if (isLeaf) { + // increment self cost for leaf + locationCost.selfCost += cost; } } -std::pair mergeAllocations(Parser *parser, const ParserData& data) +std::pair mergeAllocations(Parser* parser, const ParserData& data, + std::shared_ptr resultData) { CallerCalleeResults callerCalleeResults; TreeData topRows; - QSet symbolRecursionGuard; - auto addRow = [&symbolRecursionGuard, &callerCalleeResults](TreeData* rows, const Location& location, - const Allocation& cost) -> TreeData* { + tsl::robin_set traceRecursionGuard; + traceRecursionGuard.reserve(128); + tsl::robin_set symbolRecursionGuard; + symbolRecursionGuard.reserve(128); + auto addRow = [&symbolRecursionGuard, &callerCalleeResults](QVector* rows, const Location& location, + const Allocation& cost) -> QVector* { auto it = lower_bound(rows->begin(), rows->end(), location.symbol); if (it != rows->end() && it->symbol == location.symbol) { it->cost += cost; @@ -357,24 +358,25 @@ std::pair mergeAllocations(Parser *parser, const // merge allocations, leave parent pointers invalid (their location may change) for (const auto& allocation : data.allocations) { auto traceIndex = allocation.traceIndex; - auto rows = &topRows; - unordered_set recursionGuard; - recursionGuard.insert(traceIndex.index); + auto rows = &topRows.rows; + traceRecursionGuard.clear(); + traceRecursionGuard.insert(traceIndex); symbolRecursionGuard.clear(); - while (traceIndex) { + bool first = true; + while (traceIndex || first) { + first = false; const auto& trace = data.findTrace(traceIndex); const auto& ip = data.findIp(trace.ipIndex); - auto location = data.stringCache.location(ip); - rows = addRow(rows, location, allocation); + rows = addRow(rows, location(ip), allocation); for (const auto& inlined : ip.inlined) { - auto inlinedLocation = data.stringCache.frameLocation(inlined, ip.moduleIndex); + const auto& inlinedLocation = frameLocation(inlined, ip.moduleIndex); rows = addRow(rows, inlinedLocation, allocation); } if (data.isStopIndex(ip.frame.functionIndex)) { break; } traceIndex = trace.parentIndex; - if (!recursionGuard.insert(traceIndex.index).second) { + if (!traceRecursionGuard.insert(traceIndex).second) { qWarning() << "Trace recursion detected - corrupt data file?"; break; } @@ -386,22 +388,19 @@ std::pair mergeAllocations(Parser *parser, const } } // now set the parents, the data is constant from here on - setParents(topRows, nullptr); + setParents(topRows.rows, nullptr); + topRows.resultData = std::move(resultData); return {topRows, callerCalleeResults}; } -RowData* findBySymbol(const RowData& row, QVector* data) +RowData* findBySymbol(Symbol symbol, QVector* data) { - for (int i = 0; i < data->size(); ++i) { - if (data->at(i).symbol == row.symbol) { - return data->data() + i; - } - } - return nullptr; + auto it = std::find_if(data->begin(), data->end(), [symbol](const RowData& row) { return row.symbol == symbol; }); + return it == data->end() ? nullptr : &(*it); } -AllocationData buildTopDown(const TreeData& bottomUpData, TreeData* topDownData) +AllocationData buildTopDown(const QVector& bottomUpData, QVector* topDownData) { AllocationData totalCost; for (const auto& row : bottomUpData) { @@ -415,7 +414,7 @@ AllocationData buildTopDown(const TreeData& bottomUpData, TreeData* topDownData) auto node = &row; auto stack = topDownData; while (node) { - auto data = findBySymbol(*node, stack); + auto data = findBySymbol(node->symbol, stack); if (!data) { // create an empty top-down item for this bottom-up node *stack << RowData {{}, node->symbol, nullptr, {}}; @@ -433,21 +432,41 @@ AllocationData buildTopDown(const TreeData& bottomUpData, TreeData* topDownData) return totalCost; } -QVector toTopDownData(const QVector& bottomUpData) +TreeData toTopDownData(const TreeData& bottomUpData) { - QVector topRows; - buildTopDown(bottomUpData, &topRows); + TreeData topRows; + topRows.resultData = bottomUpData.resultData; + buildTopDown(bottomUpData.rows, &topRows.rows); // now set the parents, the data is constant from here on - setParents(topRows, nullptr); + setParents(topRows.rows, nullptr); return topRows; } -AllocationData buildCallerCallee(const TreeData& bottomUpData, CallerCalleeResults* callerCalleeResults) +struct ReusableGuardBuffer +{ + ReusableGuardBuffer() + { + recursionGuard.reserve(128); + callerCalleeRecursionGuard.reserve(128); + } + + void reset() + { + recursionGuard.clear(); + callerCalleeRecursionGuard.clear(); + } + + tsl::robin_set recursionGuard; + tsl::robin_set> callerCalleeRecursionGuard; +}; + +AllocationData buildCallerCallee(const QVector& bottomUpData, CallerCalleeResults* callerCalleeResults, + ReusableGuardBuffer* guardBuffer) { AllocationData totalCost; for (const auto& row : bottomUpData) { // recurse to find a leaf - const auto childCost = buildCallerCallee(row.children, callerCalleeResults); + const auto childCost = buildCallerCallee(row.children, callerCalleeResults, guardBuffer); if (childCost != row.cost) { // this row is (partially) a leaf const auto cost = row.cost - childCost; @@ -455,21 +474,22 @@ AllocationData buildCallerCallee(const TreeData& bottomUpData, CallerCalleeResul // leaf node found, bubble up the parent chain to add cost for all frames // to the caller/callee data. this is done top-down since we must not count // symbols more than once in the caller-callee data - QSet recursionGuard; + guardBuffer->reset(); + auto& recursionGuard = guardBuffer->recursionGuard; + auto& callerCalleeRecursionGuard = guardBuffer->callerCalleeRecursionGuard; + auto node = &row; - QSet> callerCalleeRecursionGuard; Symbol lastSymbol; CallerCalleeEntry* lastEntry = nullptr; while (node) { - const auto& symbol = node->symbol; + const auto symbol = node->symbol; // aggregate caller-callee data - auto& entry = callerCalleeResults->entry(symbol); - if (!recursionGuard.contains(symbol)) { + auto& entry = callerCalleeResults->entries[symbol]; + if (recursionGuard.insert(symbol).second) { // only increment inclusive cost once for a given stack entry.inclusiveCost += cost; - recursionGuard.insert(symbol); } if (!node->parent) { // always increment the self cost @@ -478,11 +498,9 @@ AllocationData buildCallerCallee(const TreeData& bottomUpData, CallerCalleeResul // add current entry as callee to last entry // and last entry as caller to current entry if (lastEntry) { - const auto callerCalleePair = qMakePair(symbol, lastSymbol); - if (!callerCalleeRecursionGuard.contains(callerCalleePair)) { - lastEntry->callee(symbol) += cost; - entry.caller(lastSymbol) += cost; - callerCalleeRecursionGuard.insert(callerCalleePair); + if (callerCalleeRecursionGuard.insert({symbol, lastSymbol}).second) { + lastEntry->callees[symbol] += cost; + entry.callers[lastSymbol] += cost; } } @@ -500,7 +518,8 @@ CallerCalleeResults toCallerCalleeData(const TreeData& bottomUpData, const Calle { // copy the source map and continue from there auto callerCalleeResults = results; - callerCalleeResults.totalCosts = buildCallerCallee(bottomUpData, &callerCalleeResults); + ReusableGuardBuffer guardBuffer; + buildCallerCallee(bottomUpData.rows, &callerCalleeResults, &guardBuffer); if (diffMode) { // remove rows without cost @@ -513,6 +532,7 @@ CallerCalleeResults toCallerCalleeData(const TreeData& bottomUpData, const Calle } } + callerCalleeResults.resultData = bottomUpData.resultData; return callerCalleeResults; } @@ -520,13 +540,14 @@ struct MergedHistogramColumnData { Symbol symbol; int64_t allocations; + int64_t totalAllocated; bool operator<(const Symbol& rhs) const { return symbol < rhs; } }; -HistogramData buildSizeHistogram(ParserData& data) +HistogramData buildSizeHistogram(ParserData& data, std::shared_ptr resultData) { HistogramData ret; if (data.allocationInfoCounter.empty()) { @@ -552,39 +573,43 @@ HistogramData buildSizeHistogram(ParserData& data) auto insertColumns = [&]() { sort(columnData.begin(), columnData.end(), [](const MergedHistogramColumnData& lhs, const MergedHistogramColumnData& rhs) { - return lhs.allocations > rhs.allocations; + return std::tie(lhs.allocations, lhs.totalAllocated) > std::tie(rhs.allocations, rhs.totalAllocated); }); // -1 to account for total row for (size_t i = 0; i < min(columnData.size(), size_t(HistogramRow::NUM_COLUMNS - 1)); ++i) { const auto& column = columnData[i]; - row.columns[i + 1] = {column.allocations, column.symbol}; + row.columns[i + 1] = {column.allocations, column.totalAllocated, column.symbol}; } }; for (const auto& info : data.allocationInfoCounter) { if (info.info.size > row.size) { insertColumns(); columnData.clear(); - ret << row; + ret.rows << row; ++bucketIndex; row.size = buckets[bucketIndex].first; row.sizeLabel = buckets[bucketIndex].second; - row.columns[0] = {info.allocations, {}}; + row.columns[0] = {info.allocations, static_cast(info.info.size * info.allocations), {}}; } else { - row.columns[0].allocations += info.allocations; + auto& column = row.columns[0]; + column.allocations += info.allocations; + column.totalAllocated += info.info.size * info.allocations; } const auto& allocation = data.allocations[info.info.allocationIndex.index]; - const auto ipIndex = data.findTrace(allocation.traceIndex).ipIndex; - const auto ip = data.findIp(ipIndex); - const auto location = data.stringCache.location(ip); - auto it = lower_bound(columnData.begin(), columnData.end(), location.symbol); - if (it == columnData.end() || it->symbol != location.symbol) { - columnData.insert(it, {location.symbol, info.allocations}); + const auto& ipIndex = data.findTrace(allocation.traceIndex).ipIndex; + const auto& ip = data.findIp(ipIndex); + const auto& sym = symbol(ip); + auto it = lower_bound(columnData.begin(), columnData.end(), sym); + if (it == columnData.end() || it->symbol != sym) { + columnData.insert(it, {sym, info.allocations, static_cast(info.info.size * info.allocations)}); } else { it->allocations += info.allocations; + it->totalAllocated += static_cast(info.info.size * info.allocations); } } insertColumns(); - ret << row; + ret.rows << row; + ret.resultData = std::move(resultData); return ret; } } @@ -597,19 +622,60 @@ Parser::Parser(QObject* parent) Parser::~Parser() = default; -void Parser::parse(const QString& path, const QString& diffBase) +bool Parser::isFiltered() const +{ + if (!m_data) + return false; + return m_data->filterParameters.isFilteredByTime(m_data->totalTime); +} + +void Parser::parse(const QString& path, const QString& diffBase, const FilterParameters& filterParameters, + StopAfter stopAfter) +{ + parseImpl(path, diffBase, filterParameters, stopAfter); +} + +void Parser::parseImpl(const QString& path, const QString& diffBase, const FilterParameters& filterParameters, + StopAfter stopAfter) { + auto oldData = std::move(m_data); using namespace ThreadWeaver; - stream() << make_job([this, path, diffBase]() { + stream() << make_job([this, oldData, path, diffBase, filterParameters, stopAfter]() { + const auto isReparsing = (path == m_path && oldData && diffBase.isEmpty()); + auto parsingMsg = isReparsing ? i18n("reparsing data") : i18n("parsing data"); + + auto updateProgress = [this, parsingMsg, lastPassCompletion = 0.f](const ParserData& data) mutable { + auto passCompletion = 1.0 * data.parsingState.readCompressedByte / data.parsingState.fileSize; + if (std::abs(lastPassCompletion - passCompletion) < 0.001) { + // don't spam the progress bar + return; + } + + lastPassCompletion = passCompletion; + const auto numPasses = data.diffMode ? 2 : 3; + auto totalCompletion = (data.parsingState.pass + passCompletion) / numPasses; + auto spentTime_ms = data.parseTimer.elapsed(); + auto totalRemainingTime_ms = (spentTime_ms / totalCompletion) * (1.0 - totalCompletion); + auto message = i18n("%1 pass: %2/%3 spent: %4 remaining: %5", parsingMsg, data.parsingState.pass + 1, + numPasses, Util::formatTime(spentTime_ms), Util::formatTime(totalRemainingTime_ms)); + + emit progressMessageAvailable(message); + emit progress(1000 * totalCompletion); // range is set as 0 to 1000 for fractional % bar display + }; + const auto stdPath = path.toStdString(); - auto data = make_shared(); - emit progressMessageAvailable(i18n("parsing data...")); + auto data = isReparsing ? oldData : make_shared(updateProgress); + data->filterParameters = filterParameters; + + emit progressMessageAvailable(parsingMsg); + data->parseTimer.start(); if (!diffBase.isEmpty()) { - ParserData diffData; - auto readBase = - async(launch::async, [&diffData, diffBase]() { return diffData.read(diffBase.toStdString()); }); - if (!data->read(stdPath)) { + ParserData diffData(nullptr); // currently we don't track the progress of diff parsing + auto readBase = async(launch::async, [&diffData, diffBase, isReparsing]() { + return diffData.read(diffBase.toStdString(), isReparsing); + }); + if (!data->read(stdPath, isReparsing)) { emit failedToOpen(path); return; } @@ -618,55 +684,107 @@ void Parser::parse(const QString& path, const QString& diffBase) return; } data->diff(diffData); - data->stringCache.diffMode = true; - } else if (!data->read(stdPath)) { - emit failedToOpen(path); - return; + data->diffMode = true; + } else { + if (!data->read(stdPath, isReparsing)) { + emit failedToOpen(path); + return; + } + } + + if (!isReparsing) { + data->qtStrings.resize(data->strings.size()); + std::transform(data->strings.begin(), data->strings.end(), data->qtStrings.begin(), + [](const std::string& string) { return QString::fromStdString(string); }); } - data->updateStringCache(); + data->applyLeakSuppressions(); - emit summaryAvailable({QString::fromStdString(data->debuggee), data->totalCost, data->totalTime, data->peakTime, - data->peakRSS * data->systemInfo.pageSize, - data->systemInfo.pages * data->systemInfo.pageSize, data->fromAttached}); + const auto resultData = std::make_shared(data->totalCost, data->qtStrings); + + emit summaryAvailable({QString::fromStdString(data->debuggee), data->totalCost, data->totalTime, + data->filterParameters, data->peakTime, data->peakRSS * data->systemInfo.pageSize, + data->systemInfo.pages * data->systemInfo.pageSize, data->fromAttached, + data->totalLeakedSuppressed, toQt(data->suppressions)}); + + if (stopAfter == StopAfter::Summary) { + emit finished(); + return; + } emit progressMessageAvailable(i18n("merging allocations...")); // merge allocations before modifying the data again - const auto mergedAllocations = mergeAllocations(this, *data); + const auto mergedAllocations = mergeAllocations(this, *data, resultData); emit bottomUpDataAvailable(mergedAllocations.first); + if (stopAfter == StopAfter::BottomUp) { + emit finished(); + return; + } + // also calculate the size histogram emit progressMessageAvailable(i18n("building size histogram...")); - const auto sizeHistogram = buildSizeHistogram(*data); + const auto sizeHistogram = buildSizeHistogram(*data, resultData); emit sizeHistogramDataAvailable(sizeHistogram); // now data can be modified again for the chart data evaluation - const auto diffMode = data->stringCache.diffMode; + if (stopAfter == StopAfter::SizeHistogram) { + emit finished(); + return; + } + + emit progress(0); + + const auto diffMode = data->diffMode; emit progressMessageAvailable(i18n("building charts...")); auto parallel = new Collection; - *parallel << make_job([this, mergedAllocations]() { + *parallel << make_job([this, mergedAllocations, resultData]() { const auto topDownData = toTopDownData(mergedAllocations.first); emit topDownDataAvailable(topDownData); }) << make_job([this, mergedAllocations, diffMode]() { emit callerCalleeDataAvailable( toCallerCalleeData(mergedAllocations.first, mergedAllocations.second, diffMode)); }); - if (!data->stringCache.diffMode) { + if (!data->diffMode && stopAfter != StopAfter::TopDownAndCallerCallee) { // only build charts when we are not diffing - *parallel << make_job([this, data, stdPath]() { + *parallel << make_job([this, data, stdPath, isReparsing, resultData]() { // this mutates data, and thus anything running in parallel must // not access data - data->prepareBuildCharts(); - data->read(stdPath); + data->prepareBuildCharts(resultData); + data->read(stdPath, AccumulatedTraceData::ThirdPass, isReparsing); emit consumedChartDataAvailable(data->consumedChartData); emit allocationsChartDataAvailable(data->allocationsChartData); emit temporaryChartDataAvailable(data->temporaryChartData); }); } + emit progress(0); + auto sequential = new Sequence; - *sequential << parallel << make_job([this]() { emit finished(); }); + *sequential << parallel << make_job([this, data, path]() { + QMetaObject::invokeMethod(this, [this, data, path]() { + Q_ASSERT(QThread::currentThread() == thread()); + m_data = data; + m_data->clearForReparse(); + m_path = path; + emit finished(); + }); + }); stream() << sequential; }); } + +void Parser::reparse(const FilterParameters& parameters_) +{ + if (!m_data || m_data->diffMode) + return; + + auto filterParameters = parameters_; + filterParameters.minTime = std::max(int64_t(0), filterParameters.minTime); + filterParameters.maxTime = std::min(m_data->totalTime, filterParameters.maxTime); + + parseImpl(m_path, {}, filterParameters, StopAfter::Finished); +} + +#include "moc_parser.cpp" diff --git a/src/analyze/gui/parser.h b/src/analyze/gui/parser.h index 3f3cf646..e00f086f 100644 --- a/src/analyze/gui/parser.h +++ b/src/analyze/gui/parser.h @@ -1,31 +1,24 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef PARSER_H #define PARSER_H #include +#include "../filterparameters.h" #include "callercalleemodel.h" #include "chartmodel.h" #include "histogrammodel.h" #include "treemodel.h" +#include + +struct ParserData; + class Parser : public QObject { Q_OBJECT @@ -33,11 +26,24 @@ class Parser : public QObject explicit Parser(QObject* parent = nullptr); virtual ~Parser(); -public slots: - void parse(const QString& path, const QString& diffBase); + bool isFiltered() const; + + enum class StopAfter + { + Summary, + BottomUp, + SizeHistogram, + TopDownAndCallerCallee, + Finished, + }; + + void parse(const QString& path, const QString& diffBase, const FilterParameters& filterParameters, + StopAfter stopAfter = StopAfter::Finished); + void reparse(const FilterParameters& filterParameters); signals: void progressMessageAvailable(const QString& progress); + void progress(const int progress); void summaryAvailable(const SummaryData& summary); void bottomUpDataAvailable(const TreeData& data); void topDownDataAvailable(const TreeData& data); @@ -48,6 +54,13 @@ public slots: void sizeHistogramDataAvailable(const HistogramData& data); void finished(); void failedToOpen(const QString& path); + +private: + void parseImpl(const QString& path, const QString& diffBase, const FilterParameters& filterParameters, + StopAfter stopAfter); + + QString m_path; + std::shared_ptr m_data; }; #endif // PARSER_H diff --git a/src/analyze/gui/proxystyle.cpp b/src/analyze/gui/proxystyle.cpp new file mode 100644 index 00000000..05c14368 --- /dev/null +++ b/src/analyze/gui/proxystyle.cpp @@ -0,0 +1,19 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include "proxystyle.h" + +#include + +int ProxyStyle::styleHint(QStyle::StyleHint hint, const QStyleOption* option, const QWidget* widget, + QStyleHintReturn* returnData) const +{ + if (hint == QStyle::SH_RubberBand_Mask + && widget->metaObject()->className() == QByteArrayLiteral("ChartRubberBand")) { + return 0; + } + return QProxyStyle::styleHint(hint, option, widget, returnData); +} diff --git a/src/analyze/gui/proxystyle.h b/src/analyze/gui/proxystyle.h new file mode 100644 index 00000000..adde16e9 --- /dev/null +++ b/src/analyze/gui/proxystyle.h @@ -0,0 +1,19 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#ifndef PROXYSTYLE_H +#define PROXYSTYLE_H + +#include + +class ProxyStyle : public QProxyStyle +{ +public: + int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, + QStyleHintReturn* returnData = nullptr) const override; +}; + +#endif // PROXYSTYLE_H diff --git a/src/analyze/gui/resultdata.h b/src/analyze/gui/resultdata.h new file mode 100644 index 00000000..7ffbb8cc --- /dev/null +++ b/src/analyze/gui/resultdata.h @@ -0,0 +1,50 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#ifndef RESULTDATA_H +#define RESULTDATA_H + +#include + +#include "locationdata.h" +#include "util.h" + +#include + +#include + +class ResultData +{ +public: + ResultData(AllocationData totalCosts, QVector strings) + : m_totalCosts(std::move(totalCosts)) + , m_strings(std::move(strings)) + { + } + + QString string(StringIndex stringId) const + { + return m_strings.value(stringId.index - 1); + } + + QString string(FunctionIndex functionIndex) const + { + return functionIndex ? string(static_cast(functionIndex)) : Util::unresolvedFunctionName(); + } + + const AllocationData& totalCosts() const + { + return m_totalCosts; + } + +private: + AllocationData m_totalCosts; + QVector m_strings; +}; + +Q_DECLARE_METATYPE(const ResultData*) + +#endif // RESULTDATA_H diff --git a/src/analyze/gui/stacksmodel.cpp b/src/analyze/gui/stacksmodel.cpp index b67d0de5..3f95d82a 100644 --- a/src/analyze/gui/stacksmodel.cpp +++ b/src/analyze/gui/stacksmodel.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "stacksmodel.h" #include "treemodel.h" @@ -67,7 +55,7 @@ void StacksModel::fillFromIndex(const QModelIndex& index) m_data.resize(leafs.size()); m_stackIndex = 0; int stackIndex = 0; - foreach (QModelIndex leaf, leafs) { + for (auto leaf : leafs) { auto& stack = m_data[stackIndex]; while (leaf.isValid()) { stack << leaf.sibling(leaf.row(), TreeModel::LocationColumn); @@ -112,3 +100,5 @@ QVariant StacksModel::headerData(int section, Qt::Orientation orientation, int r } return {}; } + +#include "moc_stacksmodel.cpp" diff --git a/src/analyze/gui/stacksmodel.h b/src/analyze/gui/stacksmodel.h index b56aae0e..6a77105e 100644 --- a/src/analyze/gui/stacksmodel.h +++ b/src/analyze/gui/stacksmodel.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef STACKSMODEL_H #define STACKSMODEL_H diff --git a/src/analyze/gui/summarydata.h b/src/analyze/gui/summarydata.h index ab92e963..db4a2b76 100644 --- a/src/analyze/gui/summarydata.h +++ b/src/analyze/gui/summarydata.h @@ -1,37 +1,48 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef SUMMARYDATA_H #define SUMMARYDATA_H #include "../allocationdata.h" +#include "../filterparameters.h" +#include "../suppressions.h" + #include #include +#include struct SummaryData { + SummaryData() = default; + SummaryData(const QString& debuggee, const AllocationData& cost, int64_t totalTime, + const FilterParameters& filterParameters, int64_t peakTime, int64_t peakRSS, int64_t totalSystemMemory, + bool fromAttached, int64_t totalLeakedSuppressed, QVector suppressions) + : debuggee(debuggee) + , cost(cost) + , totalLeakedSuppressed(totalLeakedSuppressed) + , totalTime(totalTime) + , filterParameters(filterParameters) + , peakTime(peakTime) + , peakRSS(peakRSS) + , totalSystemMemory(totalSystemMemory) + , fromAttached(fromAttached) + , suppressions(std::move(suppressions)) + { + } QString debuggee; AllocationData cost; - int64_t totalTime; - int64_t peakTime; - int64_t peakRSS; - int64_t totalSystemMemory; - bool fromAttached; + int64_t totalLeakedSuppressed = 0; + int64_t totalTime = 0; + FilterParameters filterParameters; + int64_t peakTime = 0; + int64_t peakRSS = 0; + int64_t totalSystemMemory = 0; + bool fromAttached = false; + QVector suppressions; }; Q_DECLARE_METATYPE(SummaryData) diff --git a/src/analyze/gui/suppressionsmodel.cpp b/src/analyze/gui/suppressionsmodel.cpp new file mode 100644 index 00000000..67e00f59 --- /dev/null +++ b/src/analyze/gui/suppressionsmodel.cpp @@ -0,0 +1,115 @@ +/* + SPDX-FileCopyrightText: 2021 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include "suppressionsmodel.h" + +#include + +#include +#include + +SuppressionsModel::SuppressionsModel(QObject* parent) + : QAbstractTableModel(parent) +{ +} + +SuppressionsModel::~SuppressionsModel() = default; + +void SuppressionsModel::setSuppressions(const SummaryData& summaryData) +{ + beginResetModel(); + m_suppressions = summaryData.suppressions; + m_totalAllocations = summaryData.cost.allocations; + m_totalLeaked = summaryData.cost.leaked; + endResetModel(); +} + +int SuppressionsModel::columnCount(const QModelIndex& parent) const +{ + if (parent.isValid() || m_suppressions.empty()) { + return 0; + } + return static_cast(Columns::COLUMN_COUNT); +} + +int SuppressionsModel::rowCount(const QModelIndex& parent) const +{ + return parent.isValid() ? 0 : static_cast(m_suppressions.size()); +} + +QVariant SuppressionsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (section < 0 || section >= columnCount() || orientation != Qt::Horizontal || role != Qt::DisplayRole) { + return {}; + } + + switch (static_cast(section)) { + case Columns::Matches: + return tr("Matches"); + case Columns::Leaked: + return tr("Leaked"); + case Columns::Pattern: + return tr("Pattern"); + case Columns::COLUMN_COUNT: + break; + } + return {}; +} + +QVariant SuppressionsModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || index.parent().isValid() || index.column() >= columnCount() || index.row() >= rowCount()) { + return {}; + } + + const auto& suppression = m_suppressions[index.row()]; + + if (role == Qt::ToolTipRole) { + return tr("Suppression rule: %1
" + "Matched Allocations: %2
  %3% out of %4 total
" + "Suppressed Leaked Memory: %5
  %6% out of %7 total
") + .arg(QString::fromStdString(suppression.pattern), QString::number(suppression.matches), + Util::formatCostRelative(suppression.matches, m_totalAllocations), QString::number(m_totalAllocations), + Util::formatBytes(suppression.leaked), Util::formatCostRelative(suppression.leaked, m_totalLeaked), + Util::formatBytes(m_totalLeaked)); + } + + switch (static_cast(index.column())) { + case Columns::Matches: + if (role == Qt::DisplayRole || role == SortRole) { + return static_cast(suppression.matches); + } else if (role == Qt::InitialSortOrderRole) { + return Qt::DescendingOrder; + } else if (role == TotalCostRole) { + return m_totalAllocations; + } + break; + case Columns::Leaked: + if (role == Qt::DisplayRole) { + return Util::formatBytes(suppression.leaked); + } else if (role == SortRole) { + return static_cast(suppression.leaked); + } else if (role == Qt::InitialSortOrderRole) { + return Qt::DescendingOrder; + } else if (role == TotalCostRole) { + return m_totalLeaked; + } + break; + case Columns::Pattern: + if (role == Qt::DisplayRole || role == SortRole) { + return QString::fromStdString(suppression.pattern); + } else if (role == Qt::InitialSortOrderRole) { + return Qt::AscendingOrder; + } + break; + case Columns::COLUMN_COUNT: + break; + } + + return {}; +} + +#include "moc_suppressionsmodel.cpp" diff --git a/src/analyze/gui/suppressionsmodel.h b/src/analyze/gui/suppressionsmodel.h new file mode 100644 index 00000000..8f88aac7 --- /dev/null +++ b/src/analyze/gui/suppressionsmodel.h @@ -0,0 +1,51 @@ +/* + SPDX-FileCopyrightText: 2021 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#ifndef SUPPRESSIONSMODEL_H +#define SUPPRESSIONSMODEL_H + +#include +#include + +struct Suppression; +struct SummaryData; + +class SuppressionsModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit SuppressionsModel(QObject* parent = nullptr); + ~SuppressionsModel(); + + void setSuppressions(const SummaryData& summaryData); + + enum class Columns + { + Matches, + Leaked, + Pattern, + COLUMN_COUNT, + }; + int columnCount(const QModelIndex& parent = {}) const override; + int rowCount(const QModelIndex& parent = {}) const override; + + enum Roles + { + SortRole = Qt::UserRole, + TotalCostRole, + }; + + QVariant headerData(int section, Qt::Orientation orientation = Qt::Horizontal, + int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + +private: + QVector m_suppressions; + qint64 m_totalAllocations = 0; + qint64 m_totalLeaked = 0; +}; + +#endif // SUPPRESSIONSMODEL_H diff --git a/src/analyze/gui/topproxy.cpp b/src/analyze/gui/topproxy.cpp index 5d9947a0..d1c26060 100644 --- a/src/analyze/gui/topproxy.cpp +++ b/src/analyze/gui/topproxy.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "topproxy.h" @@ -82,3 +70,5 @@ void TopProxy::updateCostThreshold() m_costThreshold = sourceModel()->index(0, toSource(m_type)).data(TreeModel::MaxCostRole).toLongLong() * 0.01; invalidate(); } + +#include "moc_topproxy.cpp" diff --git a/src/analyze/gui/topproxy.h b/src/analyze/gui/topproxy.h index fd0f806d..e06ab9a6 100644 --- a/src/analyze/gui/topproxy.h +++ b/src/analyze/gui/topproxy.h @@ -1,20 +1,8 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TOPPROXY_H #define TOPPROXY_H diff --git a/src/analyze/gui/treemodel.cpp b/src/analyze/gui/treemodel.cpp index dc19e6c7..c070e1d1 100644 --- a/src/analyze/gui/treemodel.cpp +++ b/src/analyze/gui/treemodel.cpp @@ -1,43 +1,31 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "treemodel.h" #include #include -#include #include #include +#include "resultdata.h" #include "util.h" namespace { -int indexOf(const RowData* row, const TreeData& siblings) +int indexOf(const RowData* row, const QVector& siblings) { Q_ASSERT(siblings.data() <= row); Q_ASSERT(siblings.data() + siblings.size() > row); return row - siblings.data(); } -const RowData* rowAt(const TreeData& rows, int row) +const RowData* rowAt(const QVector& rows, int row) { Q_ASSERT(rows.size() > row); return rows.data() + row; @@ -73,10 +61,6 @@ QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int rol } if (role == Qt::DisplayRole) { switch (static_cast(section)) { - case FunctionColumn: - return i18n("Function"); - case ModuleColumn: - return i18n("Module"); case AllocationsColumn: return i18n("Allocations"); case TemporaryColumn: @@ -92,13 +76,6 @@ QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int rol } } else if (role == Qt::ToolTipRole) { switch (static_cast(section)) { - case FunctionColumn: - return i18n("The parent function that called an allocation function. " - "May be unknown when debug information is missing."); - case ModuleColumn: - return i18n("The module, i.e. executable or shared library, from " - "which an allocation function was " - "called."); case AllocationsColumn: return i18n("The number of times an allocation function was called " "from this location."); @@ -150,42 +127,37 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const if (role == SortRole || role == MaxCostRole) { return static_cast(abs(row->cost.peak)); } else { - return m_format.formatByteSize(row->cost.peak, 1, KFormat::MetricBinaryDialect); + return Util::formatBytes(row->cost.peak); } case LeakedColumn: if (role == SortRole || role == MaxCostRole) { return static_cast(abs(row->cost.leaked)); } else { - return m_format.formatByteSize(row->cost.leaked, 1, KFormat::MetricBinaryDialect); + return Util::formatBytes(row->cost.leaked); } - case FunctionColumn: - return row->symbol.symbol; - case ModuleColumn: - return row->symbol.binary; case LocationColumn: - return i18n("%1 in %2 (%3)", row->symbol.symbol, row->symbol.binary, row->symbol.path); + return Util::toString(row->symbol, *m_data.resultData, Util::Short); case NUM_COLUMNS: break; } } else if (role == Qt::ToolTipRole) { + auto toStr = [this](StringIndex stringId) { return m_data.resultData->string(stringId); }; QString tooltip; QTextStream stream(&tooltip); stream << "
";
+        const auto module = toStr(row->symbol.moduleId);
         stream << i18nc("1: function, 2: module, 3: module path", "%1\n  in %2 (%3)",
-                        row->symbol.symbol.toHtmlEscaped(), row->symbol.binary.toHtmlEscaped(),
-                        row->symbol.path.toHtmlEscaped());
+                        toStr(row->symbol.functionId).toHtmlEscaped(), Util::basename(module).toHtmlEscaped(),
+                        module.toHtmlEscaped());
         stream << '\n';
         stream << '\n';
-        KFormat format;
         const auto peakFraction = Util::formatCostRelative(row->cost.peak, m_maxCost.cost.peak);
         const auto leakedFraction = Util::formatCostRelative(row->cost.leaked, m_maxCost.cost.leaked);
         const auto allocationsFraction = Util::formatCostRelative(row->cost.allocations, m_maxCost.cost.allocations);
         const auto temporaryFraction = Util::formatCostRelative(row->cost.temporary, row->cost.allocations);
         const auto temporaryFractionTotal = Util::formatCostRelative(row->cost.temporary, m_maxCost.cost.temporary);
-        stream << i18n("peak contribution: %1 (%2% of total)\n",
-                       format.formatByteSize(row->cost.peak, 1, KFormat::MetricBinaryDialect), peakFraction);
-        stream << i18n("leaked: %1 (%2% of total)\n",
-                       format.formatByteSize(row->cost.leaked, 1, KFormat::MetricBinaryDialect), leakedFraction);
+        stream << i18n("peak contribution: %1 (%2% of total)\n", Util::formatBytes(row->cost.peak), peakFraction);
+        stream << i18n("leaked: %1 (%2% of total)\n", Util::formatBytes(row->cost.leaked), leakedFraction);
         stream << i18n("allocations: %1 (%2% of total)\n", row->cost.allocations, allocationsFraction);
         stream << i18n("temporary: %1 (%2% of allocations, %3% of total)\n", row->cost.temporary, temporaryFraction,
                        temporaryFractionTotal);
@@ -197,9 +169,10 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const
             }
             while (child->children.count() == 1 && max-- > 0) {
                 stream << "\n";
+                const auto module = toStr(child->symbol.moduleId);
                 stream << i18nc("1: function, 2: module, 3: module path", "%1\n  in %2 (%3)",
-                                child->symbol.symbol.toHtmlEscaped(), child->symbol.binary.toHtmlEscaped(),
-                                child->symbol.path.toHtmlEscaped());
+                                toStr(child->symbol.functionId).toHtmlEscaped(), Util::basename(module).toHtmlEscaped(),
+                                module.toHtmlEscaped());
                 child = child->children.data();
             }
             if (child->children.count() > 1) {
@@ -211,6 +184,8 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const
         return tooltip;
     } else if (role == SymbolRole) {
         return QVariant::fromValue(row->symbol);
+    } else if (role == ResultDataRole) {
+        return QVariant::fromValue(m_data.resultData.get());
     }
     return {};
 }
@@ -238,7 +213,7 @@ QModelIndex TreeModel::parent(const QModelIndex& child) const
 int TreeModel::rowCount(const QModelIndex& parent) const
 {
     if (!parent.isValid()) {
-        return m_data.size();
+        return m_data.rows.size();
     } else if (parent.column() != 0) {
         return 0;
     }
@@ -254,6 +229,7 @@ int TreeModel::columnCount(const QModelIndex& /*parent*/) const
 
 void TreeModel::resetData(const TreeData& data)
 {
+    Q_ASSERT(data.resultData);
     beginResetModel();
     m_data = data;
     endResetModel();
@@ -282,7 +258,7 @@ const RowData* TreeModel::toRow(const QModelIndex& index) const
     if (const auto parent = toParentRow(index)) {
         return rowAt(parent->children, index.row());
     } else {
-        return rowAt(m_data, index.row());
+        return rowAt(m_data.rows, index.row());
     }
 }
 
@@ -291,6 +267,8 @@ int TreeModel::rowOf(const RowData* row) const
     if (auto parent = row->parent) {
         return indexOf(row, parent->children);
     } else {
-        return indexOf(row, m_data);
+        return indexOf(row, m_data.rows);
     }
 }
+
+#include "moc_treemodel.cpp"
diff --git a/src/analyze/gui/treemodel.h b/src/analyze/gui/treemodel.h
index 8889d82d..867db637 100644
--- a/src/analyze/gui/treemodel.h
+++ b/src/analyze/gui/treemodel.h
@@ -1,20 +1,8 @@
 /*
- * Copyright 2015-2017 Milian Wolff 
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
+    SPDX-FileCopyrightText: 2015-2017 Milian Wolff 
+
+    SPDX-License-Identifier: LGPL-2.1-or-later
+*/
 
 #ifndef TREEMODEL_H
 #define TREEMODEL_H
@@ -22,12 +10,14 @@
 #include 
 #include 
 
-#include 
-
 #include "../allocationdata.h"
 #include "locationdata.h"
 #include "summarydata.h"
 
+#include 
+
+class ResultData;
+
 struct RowData
 {
     AllocationData cost;
@@ -41,7 +31,11 @@ struct RowData
 };
 Q_DECLARE_TYPEINFO(RowData, Q_MOVABLE_TYPE);
 
-using TreeData = QVector;
+struct TreeData
+{
+    QVector rows;
+    std::shared_ptr resultData;
+};
 Q_DECLARE_METATYPE(TreeData)
 
 class TreeModel : public QAbstractItemModel
@@ -53,13 +47,11 @@ class TreeModel : public QAbstractItemModel
 
     enum Columns
     {
+        LocationColumn,
         PeakColumn,
         LeakedColumn,
         AllocationsColumn,
         TemporaryColumn,
-        FunctionColumn,
-        ModuleColumn,
-        LocationColumn,
         NUM_COLUMNS
     };
 
@@ -67,7 +59,8 @@ class TreeModel : public QAbstractItemModel
     {
         SortRole = Qt::UserRole,
         MaxCostRole,
-        SymbolRole
+        SymbolRole,
+        ResultDataRole,
     };
 
     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
@@ -90,8 +83,6 @@ public slots:
 
     TreeData m_data;
     RowData m_maxCost;
-    // TODO: update via global event filter when the locale changes (changeEvent)
-    KFormat m_format;
 };
 
 #endif // TREEMODEL_H
diff --git a/src/analyze/gui/treeproxy.cpp b/src/analyze/gui/treeproxy.cpp
index 362ed7af..d1eb672a 100644
--- a/src/analyze/gui/treeproxy.cpp
+++ b/src/analyze/gui/treeproxy.cpp
@@ -1,29 +1,19 @@
 /*
- * Copyright 2015-2017 Milian Wolff 
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
+    SPDX-FileCopyrightText: 2015-2017 Milian Wolff 
+
+    SPDX-License-Identifier: LGPL-2.1-or-later
+*/
 
 #include "treeproxy.h"
+#include "locationdata.h"
 
+#include 
 #include 
 
-TreeProxy::TreeProxy(int functionColumn, int moduleColumn, QObject* parent)
+TreeProxy::TreeProxy(int symbolRole, int resultDataRole, QObject* parent)
     : QSortFilterProxyModel(parent)
-    , m_functionColumn(functionColumn)
-    , m_moduleColumn(moduleColumn)
+    , m_symbolRole(symbolRole)
+    , m_resultDataRole(resultDataRole)
 {
     setRecursiveFilteringEnabled(true);
     setSortLocaleAware(false);
@@ -49,17 +39,50 @@ bool TreeProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent)
     if (!source) {
         return false;
     }
-    if (!m_functionFilter.isEmpty()) {
-        const auto& function = source->index(sourceRow, m_functionColumn, sourceParent).data().toString();
-        if (!function.contains(m_functionFilter, Qt::CaseInsensitive)) {
-            return false;
-        }
+
+    if (m_functionFilter.isEmpty() && m_moduleFilter.isEmpty()) {
+        return true;
     }
-    if (!m_moduleFilter.isEmpty()) {
-        const auto& module = source->index(sourceRow, m_moduleColumn, sourceParent).data().toString();
-        if (!module.contains(m_moduleFilter, Qt::CaseInsensitive)) {
-            return false;
-        }
+
+    const auto index = source->index(sourceRow, 0, sourceParent);
+    const auto* resultData = index.data(m_resultDataRole).value();
+    Q_ASSERT(resultData);
+
+    auto filterOut = [&](StringIndex stringId, const QString& filter) {
+        return !filter.isEmpty() && !resultData->string(stringId).contains(filter, Qt::CaseInsensitive);
+    };
+
+    const auto symbol = index.data(m_symbolRole).value();
+    if (filterOut(symbol.functionId, m_functionFilter) || filterOut(symbol.moduleId, m_moduleFilter)) {
+        return false;
     }
     return true;
 }
+
+bool TreeProxy::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const
+{
+    if (sortColumn() != 0) {
+        return QSortFilterProxyModel::lessThan(source_left, source_right);
+    }
+
+    const auto* resultData = source_left.data(m_resultDataRole).value();
+
+    const auto symbol_left = source_left.data(m_symbolRole).value();
+    const auto symbol_right = source_right.data(m_symbolRole).value();
+
+    if (symbol_left.functionId != symbol_right.functionId) {
+        return resultData->string(symbol_left.functionId) < resultData->string(symbol_right.functionId);
+    }
+
+    const auto path_left = resultData->string(symbol_left.moduleId);
+    const auto path_right = resultData->string(symbol_right.moduleId);
+
+    auto toShortPath = [](const QString& path) {
+        int idx = path.lastIndexOf(QLatin1Char('/'));
+        return QStringView(path).mid(idx + 1);
+    };
+
+    return toShortPath(path_left) < toShortPath(path_right);
+}
+
+#include "moc_treeproxy.cpp"
diff --git a/src/analyze/gui/treeproxy.h b/src/analyze/gui/treeproxy.h
index d422069c..c1cbfe34 100644
--- a/src/analyze/gui/treeproxy.h
+++ b/src/analyze/gui/treeproxy.h
@@ -1,20 +1,8 @@
 /*
- * Copyright 2015-2017 Milian Wolff 
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
+    SPDX-FileCopyrightText: 2015-2017 Milian Wolff 
+
+    SPDX-License-Identifier: LGPL-2.1-or-later
+*/
 
 #ifndef TREEPROXY_H
 #define TREEPROXY_H
@@ -25,7 +13,7 @@ class TreeProxy final : public QSortFilterProxyModel
 {
     Q_OBJECT
 public:
-    explicit TreeProxy(int functionColumn, int moduleColumn, QObject* parent = nullptr);
+    explicit TreeProxy(int symbolRole, int resultDataRole, QObject* parent = nullptr);
     virtual ~TreeProxy();
 
 public slots:
@@ -34,9 +22,10 @@ public slots:
 
 private:
     bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
+    bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override;
 
-    int m_functionColumn;
-    int m_moduleColumn;
+    const int m_symbolRole;
+    const int m_resultDataRole;
 
     QString m_functionFilter;
     QString m_moduleFilter;
diff --git a/src/analyze/gui/util.cpp b/src/analyze/gui/util.cpp
index 85527873..f2d6f37e 100644
--- a/src/analyze/gui/util.cpp
+++ b/src/analyze/gui/util.cpp
@@ -1,28 +1,26 @@
 /*
- * Copyright 2017-2019 Milian Wolff 
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
+    SPDX-FileCopyrightText: 2017-2019 Milian Wolff 
+
+    SPDX-License-Identifier: LGPL-2.1-or-later
+*/
 
 #include "util.h"
 
 #include 
 
+#include 
+
 #include 
 #include 
 
+namespace {
+const KFormat& format()
+{
+    static const KFormat format;
+    return format;
+}
+}
+
 QString Util::basename(const QString& path)
 {
     int idx = path.lastIndexOf(QLatin1Char('/'));
@@ -36,19 +34,48 @@ QString Util::formatString(const QString& input)
 
 QString Util::formatTime(qint64 ms)
 {
-    if (ms > 60000) {
-        // minutes
-        return QString::number(double(ms) / 60000, 'g', 3) + QLatin1String("min");
-    } else {
-        // seconds
-        return QString::number(double(ms) / 1000, 'g', 3) + QLatin1Char('s');
+    auto format = [](quint64 fragment, int precision) -> QString {
+        return QString::number(fragment).rightJustified(precision, QLatin1Char('0'));
+    };
+
+    if (std::abs(ms) < 1000) {
+        QString ret = QString::number(ms) + QLatin1String("ms");
     }
+
+    const auto isNegative = ms < 0;
+    if (isNegative)
+        ms = -ms;
+    qint64 totalSeconds = ms / 1000;
+    ms = ms % 1000;
+    qint64 days = totalSeconds / 60 / 60 / 24;
+    qint64 hours = (totalSeconds / 60 / 60) % 24;
+    qint64 minutes = (totalSeconds / 60) % 60;
+    qint64 seconds = totalSeconds % 60;
+
+    auto optional = [](quint64 fragment, const char* unit) -> QString {
+        if (fragment > 0)
+            return QString::number(fragment) + QLatin1String(unit);
+        return QString();
+    };
+
+    QString ret = optional(days, "d") + optional(hours, "h") + optional(minutes, "min");
+    const auto showMs = ret.isEmpty();
+    ret += format(seconds, 2);
+    if (showMs)
+        ret += QLatin1Char('.') + format(showMs ? ms : 0, 3);
+    ret += QLatin1Char('s');
+    if (isNegative)
+        ret.prepend(QLatin1Char('-'));
+    return ret;
 }
 
 QString Util::formatBytes(qint64 bytes)
 {
-    static const KFormat format;
-    return format.formatByteSize(bytes, 1, KFormat::MetricBinaryDialect);
+    auto ret = format().formatByteSize(bytes, 1, KFormat::MetricBinaryDialect);
+    // remove spaces, otherwise HTML might break between the unit and the cost
+    // note that we also don't add a space before our time units above
+    ret.remove(QLatin1Char(' '));
+    return ret;
 }
 
 QString Util::formatCostRelative(qint64 selfCost, qint64 totalCost, bool addPercentSign)
@@ -64,10 +91,11 @@ QString Util::formatCostRelative(qint64 selfCost, qint64 totalCost, bool addPerc
     return ret;
 }
 
-QString Util::formatTooltip(const Symbol& symbol, const AllocationData& costs, const AllocationData& totalCosts)
+QString Util::formatTooltip(const Symbol& symbol, const AllocationData& costs, const ResultData& resultData)
 {
-    auto toolTip = i18n("symbol: %1
binary: %2 (%3)", symbol.symbol.toHtmlEscaped(), - symbol.binary.toHtmlEscaped(), symbol.path.toHtmlEscaped()); + const auto& totalCosts = resultData.totalCosts(); + + auto toolTip = Util::toString(symbol, resultData, Util::Long); auto formatCost = [&](const QString& label, int64_t AllocationData::*member) -> QString { const auto cost = costs.*member; @@ -89,10 +117,10 @@ QString Util::formatTooltip(const Symbol& symbol, const AllocationData& costs, c } QString Util::formatTooltip(const Symbol& symbol, const AllocationData& selfCosts, const AllocationData& inclusiveCosts, - const AllocationData& totalCosts) + const ResultData& resultData) { - auto toolTip = i18n("symbol: %1
binary: %2 (%3)", symbol.symbol.toHtmlEscaped(), - symbol.binary.toHtmlEscaped(), symbol.path.toHtmlEscaped()); + const auto& totalCosts = resultData.totalCosts(); + auto toolTip = Util::toString(symbol, resultData, Util::Long); auto formatCost = [&](const QString& label, int64_t AllocationData::*member) -> QString { const auto selfCost = selfCosts.*member; @@ -118,9 +146,10 @@ QString Util::formatTooltip(const Symbol& symbol, const AllocationData& selfCost } QString Util::formatTooltip(const FileLine& location, const AllocationData& selfCosts, - const AllocationData& inclusiveCosts, const AllocationData& totalCosts) + const AllocationData& inclusiveCosts, const ResultData& resultData) { - QString toolTip = location.toString().toHtmlEscaped(); + QString toolTip = toString(location, resultData, Util::Long).toHtmlEscaped(); + const auto& totalCosts = resultData.totalCosts(); auto formatCost = [&](const QString& label, int64_t AllocationData::*member) -> QString { const auto selfCost = selfCosts.*member; @@ -144,3 +173,39 @@ QString Util::formatTooltip(const FileLine& location, const AllocationData& self toolTip += formatCost(i18n("Temporary Allocations"), &AllocationData::temporary); return QString(QLatin1String("") + toolTip + QLatin1String("")); } + +QString Util::toString(const Symbol& symbol, const ResultData& resultData, FormatType formatType) +{ + const auto& binaryPath = resultData.string(symbol.moduleId); + const auto binaryName = Util::basename(binaryPath); + switch (formatType) { + case Long: + return i18n("symbol: %1
binary: %2 (%3)", + resultData.string(symbol.functionId).toHtmlEscaped(), binaryName.toHtmlEscaped(), + binaryPath.toHtmlEscaped()); + case Short: + return i18nc("%1: function name, %2: binary basename", "%1 in %2", resultData.string(symbol.functionId), + Util::basename(resultData.string(symbol.moduleId))); + } + Q_UNREACHABLE(); +} + +QString Util::toString(const FileLine& location, const ResultData& resultData, FormatType formatType) +{ + auto file = resultData.string(location.fileId); + switch (formatType) { + case Long: + break; + case Short: + file = Util::basename(file); + break; + } + + return file.isEmpty() ? QStringLiteral("??") : (file + QLatin1Char(':') + QString::number(location.line)); +} + +const QString& Util::unresolvedFunctionName() +{ + static QString msg = i18n(""); + return msg; +} diff --git a/src/analyze/gui/util.h b/src/analyze/gui/util.h index 4c5187fe..c3c7162e 100644 --- a/src/analyze/gui/util.h +++ b/src/analyze/gui/util.h @@ -1,20 +1,8 @@ /* - * Copyright 2017-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2017-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef UTIL_H #define UTIL_H @@ -26,17 +14,28 @@ class QString; +class ResultData; + namespace Util { QString basename(const QString& path); QString formatString(const QString& input); QString formatTime(qint64 ms); QString formatBytes(qint64 bytes); QString formatCostRelative(qint64 selfCost, qint64 totalCost, bool addPercentSign = false); -QString formatTooltip(const Symbol& symbol, const AllocationData& costs, const AllocationData& totalCosts); +QString formatTooltip(const Symbol& symbol, const AllocationData& costs, const ResultData& resultData); QString formatTooltip(const Symbol& symbol, const AllocationData& selfCosts, const AllocationData& inclusiveCosts, - const AllocationData& totalCosts); + const ResultData& resultDat); QString formatTooltip(const FileLine& location, const AllocationData& selfCosts, const AllocationData& inclusiveCosts, - const AllocationData& totalCosts); + const ResultData& resultDat); + +enum FormatType +{ + Long, + Short +}; +QString toString(const Symbol& symbol, const ResultData& resultData, FormatType formatType); +QString toString(const FileLine& location, const ResultData& resultData, FormatType formatType); +const QString& unresolvedFunctionName(); } Q_DECLARE_TYPEINFO(AllocationData, Q_MOVABLE_TYPE); diff --git a/src/analyze/print/heaptrack_print.cpp b/src/analyze/print/heaptrack_print.cpp index 2f268f0f..2ade38d1 100644 --- a/src/analyze/print/heaptrack_print.cpp +++ b/src/analyze/print/heaptrack_print.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2014-2016 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2016 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ /** * @file heaptrack_print.cpp @@ -25,11 +13,14 @@ #include #include "analyze/accumulatedtracedata.h" +#include "analyze/suppressions.h" #include #include #include +#include + #include "util/config.h" using namespace std; @@ -51,8 +42,9 @@ struct MergedAllocation : public AllocationData class formatBytes { public: - formatBytes(int64_t bytes) + formatBytes(int64_t bytes, int width = 0) : m_bytes(bytes) + , m_width(width) { } @@ -60,29 +52,39 @@ class formatBytes private: int64_t m_bytes; + int m_width; }; -ostream& operator<<(ostream& out, const formatBytes data) +template +ostream& writeBytes(ostream& out, Bytes bytes, int width, const char* unit) { - if (data.m_bytes < 0) { - // handle negative values - return out << '-' << formatBytes(-data.m_bytes); - } - if (data.m_bytes < 1000) { - // no fancy formatting for plain byte values, esp. no .00 factions - return out << data.m_bytes << 'B'; + const auto unitLength = strlen(unit); + if (width > static_cast(unitLength)) { + return out << fixed << setprecision(2) << setw(width - unitLength) << bytes << unit; + } else { + return out << fixed << setprecision(2) << bytes << *unit; } +} + +ostream& operator<<(ostream& out, const formatBytes data) +{ + auto bytes = static_cast(data.m_bytes); static const auto units = {"B", "KB", "MB", "GB", "TB"}; auto unit = units.begin(); size_t i = 0; - double bytes = data.m_bytes; - while (i < units.size() - 1 && bytes > 1000.) { + while (i < units.size() - 1 && std::abs(bytes) > 1000.) { bytes /= 1000.; ++i; ++unit; } - return out << fixed << setprecision(2) << bytes << *unit; + + if (i == 0) { + // no fractions for bytes + return writeBytes(out, data.m_bytes, data.m_width, *unit); + } else { + return writeBytes(out, bytes, data.m_width, *unit); + } } enum CostType @@ -114,6 +116,7 @@ struct Printer final : public AccumulatedTraceData { void finalize() { + applyLeakSuppressions(); filterAllocations(); mergedAllocations = mergeAllocations(allocations); } @@ -151,9 +154,7 @@ struct Printer final : public AccumulatedTraceData vector ret; ret.reserve(allocations.size()); for (const Allocation& allocation : allocations) { - if (allocation.traceIndex) { - mergeAllocation(&ret, allocation); - } + mergeAllocation(&ret, allocation); } for (MergedAllocation& merged : ret) { for (const Allocation& allocation : merged.traces) { @@ -274,8 +275,7 @@ struct Printer final : public AccumulatedTraceData void printBacktrace(TraceNode node, ostream& out, const size_t indent = 0, bool skipFirst = false) const { - unordered_set recursionGuard; - recursionGuard.insert(node.ipIndex.index); + tsl::robin_set recursionGuard; while (node.ipIndex) { const auto& ip = findIp(node.ipIndex); if (!skipFirst) { @@ -287,11 +287,10 @@ struct Printer final : public AccumulatedTraceData break; } - if (!recursionGuard.insert(node.parentIndex.index).second) { - cerr << "Trace recursion detected - corrupt data file?" << endl; + if (!recursionGuard.insert(node.parentIndex).second) { + cerr << "Trace recursion detected - corrupt data file? " << node.parentIndex.index << endl; break; } - node = findTrace(node.parentIndex); }; } @@ -340,6 +339,10 @@ struct Printer final : public AccumulatedTraceData label(allocation); printIp(allocation.ipIndex, cout); + if (!allocation.ipIndex) { + continue; + } + sort(allocation.traces.begin(), allocation.traces.end(), sortOrder); int64_t handled = 0; for (size_t j = 0; j < min(subPeakLimit, allocation.traces.size()); ++j) { @@ -512,10 +515,13 @@ struct Printer final : public AccumulatedTraceData } } - void handleTimeStamp(int64_t /*oldStamp*/, int64_t newStamp) override + void handleTimeStamp(int64_t /*oldStamp*/, int64_t newStamp, bool isFinalTimeStamp, ParsePass pass) override { + if (pass != ParsePass::FirstPass) { + return; + } if (massifOut.is_open()) { - writeMassifSnapshot(newStamp, newStamp == totalTime); + writeMassifSnapshot(newStamp, isFinalTimeStamp); } } @@ -599,6 +605,17 @@ int main(int argc, char** argv) "You can set the value to zero to disable detailed snapshots.\n") ("filter-bt-function", po::value()->default_value(string()), "Only print allocations where the backtrace contains the given function.") + ("suppressions", po::value()->default_value(string()), + "Load list of leak suppressions from the specified file. Specify one suppression per line, and start each line with 'leak:', i.e. use the LSAN suppression file format.") + ("disable-embedded-suppressions", + "Ignore suppression definitions that are embedded into the heaptrack data file. By default, heaptrack will copy the suppressions" + "optionally defined via a `const char *__lsan_default_suppressions()` symbol in the debuggee application. These are then always " + "applied when analyzing the data, unless this feature is explicitly disabled using this command line option.") + ("disable-builtin-suppressions", + "Ignore suppression definitions that are built into heaptrack. By default, heaptrack will suppress certain " + "known leaks from common system libraries.") + ("print-suppressions", po::value()->default_value(false)->implicit_value(true), + "Show statistics for matched suppressions.") ("help,h", "Show this help message.") ("version,v", "Displays version information."); // clang-format on @@ -663,20 +680,30 @@ int main(int argc, char** argv) const bool printPeaks = vm["print-peaks"].as(); const bool printAllocs = vm["print-allocators"].as(); const bool printTemporary = vm["print-temporary"].as(); + const auto printSuppressions = vm["print-suppressions"].as(); + const auto suppressionsFile = vm["suppressions"].as(); + + data.filterParameters.disableEmbeddedSuppressions = vm.count("disable-embedded-suppressions"); + data.filterParameters.disableBuiltinSuppressions = vm.count("disable-builtin-suppressions"); + bool suppressionsOk = false; + data.filterParameters.suppressions = parseSuppressions(suppressionsFile, &suppressionsOk); + if (!suppressionsOk) { + return 1; + } cout << "reading file \"" << inputFile << "\" - please wait, this might take some time..." << endl; if (!diffFile.empty()) { cout << "reading diff file \"" << diffFile << "\" - please wait, this might take some time..." << endl; Printer diffData; - auto diffRead = async(launch::async, [&diffData, diffFile]() { return diffData.read(diffFile); }); + auto diffRead = async(launch::async, [&diffData, diffFile]() { return diffData.read(diffFile, false); }); - if (!data.read(inputFile) || !diffRead.get()) { + if (!data.read(inputFile, false) || !diffRead.get()) { return 1; } data.diff(diffData); - } else if (!data.read(inputFile)) { + } else if (!data.read(inputFile, false)) { return 1; } @@ -687,73 +714,86 @@ int main(int argc, char** argv) if (printAllocs) { // sort by amount of allocations cout << "MOST CALLS TO ALLOCATION FUNCTIONS\n"; - data.printAllocations(&AllocationData::allocations, - [](const AllocationData& data) { - cout << data.allocations << " calls to allocation functions with " - << formatBytes(data.peak) << " peak consumption from\n"; - }, - [](const AllocationData& data) { - cout << data.allocations << " calls with " << formatBytes(data.peak) - << " peak consumption from:\n"; - }); + data.printAllocations( + &AllocationData::allocations, + [](const AllocationData& data) { + cout << data.allocations << " calls to allocation functions with " << formatBytes(data.peak) + << " peak consumption from\n"; + }, + [](const AllocationData& data) { + cout << data.allocations << " calls with " << formatBytes(data.peak) << " peak consumption from:\n"; + }); cout << endl; } if (printPeaks) { cout << "PEAK MEMORY CONSUMERS\n"; - data.printAllocations(&AllocationData::peak, - [](const AllocationData& data) { - cout << formatBytes(data.peak) << " peak memory consumed over " << data.allocations - << " calls from\n"; - }, - [](const AllocationData& data) { - cout << formatBytes(data.peak) << " consumed over " << data.allocations - << " calls from:\n"; - }); + data.printAllocations( + &AllocationData::peak, + [](const AllocationData& data) { + cout << formatBytes(data.peak) << " peak memory consumed over " << data.allocations << " calls from\n"; + }, + [](const AllocationData& data) { + cout << formatBytes(data.peak) << " consumed over " << data.allocations << " calls from:\n"; + }); cout << endl; } if (printLeaks) { // sort by amount of leaks cout << "MEMORY LEAKS\n"; - data.printAllocations(&AllocationData::leaked, - [](const AllocationData& data) { - cout << formatBytes(data.leaked) << " leaked over " << data.allocations - << " calls from\n"; - }, - [](const AllocationData& data) { - cout << formatBytes(data.leaked) << " leaked over " << data.allocations - << " calls from:\n"; - }); + data.printAllocations( + &AllocationData::leaked, + [](const AllocationData& data) { + cout << formatBytes(data.leaked) << " leaked over " << data.allocations << " calls from\n"; + }, + [](const AllocationData& data) { + cout << formatBytes(data.leaked) << " leaked over " << data.allocations << " calls from:\n"; + }); cout << endl; } if (printTemporary) { // sort by amount of temporary allocations cout << "MOST TEMPORARY ALLOCATIONS\n"; - data.printAllocations(&AllocationData::temporary, - [](const AllocationData& data) { - cout << data.temporary << " temporary allocations of " << data.allocations - << " allocations in total (" << fixed << setprecision(2) - << (float(data.temporary) * 100.f / data.allocations) << "%) from\n"; - }, - [](const AllocationData& data) { - cout << data.temporary << " temporary allocations of " << data.allocations - << " allocations in total (" << fixed << setprecision(2) - << (float(data.temporary) * 100.f / data.allocations) << "%) from:\n"; - }); + data.printAllocations( + &AllocationData::temporary, + [](const AllocationData& data) { + cout << data.temporary << " temporary allocations of " << data.allocations << " allocations in total (" + << fixed << setprecision(2) << (float(data.temporary) * 100.f / data.allocations) << "%) from\n"; + }, + [](const AllocationData& data) { + cout << data.temporary << " temporary allocations of " << data.allocations << " allocations in total (" + << fixed << setprecision(2) << (float(data.temporary) * 100.f / data.allocations) << "%) from:\n"; + }); cout << endl; } - const double totalTimeS = 0.001 * data.totalTime; - cout << "total runtime: " << fixed << totalTimeS << "s.\n" + const double totalTimeS = data.totalTime ? (1000. / data.totalTime) : 1.; + cout << "total runtime: " << fixed << (data.totalTime / 1000.) << "s.\n" << "calls to allocation functions: " << data.totalCost.allocations << " (" - << int64_t(data.totalCost.allocations / totalTimeS) << "/s)\n" + << int64_t(data.totalCost.allocations * totalTimeS) << "/s)\n" << "temporary memory allocations: " << data.totalCost.temporary << " (" - << int64_t(data.totalCost.temporary / totalTimeS) << "/s)\n" + << int64_t(data.totalCost.temporary * totalTimeS) << "/s)\n" << "peak heap memory consumption: " << formatBytes(data.totalCost.peak) << '\n' << "peak RSS (including heaptrack overhead): " << formatBytes(data.peakRSS * data.systemInfo.pageSize) << '\n' << "total memory leaked: " << formatBytes(data.totalCost.leaked) << '\n'; + if (data.totalLeakedSuppressed) { + cout << "suppressed leaks: " << formatBytes(data.totalLeakedSuppressed) << '\n'; + + if (printSuppressions) { + cout << "Suppressions used:\n"; + cout << setw(16) << "matches" << ' ' << setw(16) << "leaked" + << " pattern\n"; + for (const auto& suppression : data.suppressions) { + if (!suppression.matches) { + continue; + } + cout << setw(16) << suppression.matches << ' ' << formatBytes(suppression.leaked, 16) << ' ' + << suppression.pattern << '\n'; + } + } + } if (!printHistogram.empty()) { ofstream histogram(printHistogram, ios_base::out); diff --git a/src/analyze/suppressions.cpp b/src/analyze/suppressions.cpp new file mode 100644 index 00000000..5e1adf8d --- /dev/null +++ b/src/analyze/suppressions.cpp @@ -0,0 +1,133 @@ +/* + SPDX-FileCopyrightText: 2021 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include "suppressions.h" + +#include +#include +#include + +#include + +namespace { +std::vector parseSuppressionsFile(std::istream& input) +{ + std::vector ret; + std::string line; + while (std::getline(input, line)) { + auto suppression = parseSuppression(line); + if (!suppression.empty()) { + ret.push_back(std::move(suppression)); + } + } + return ret; +} + +/** + * This function is based on the TemplateMatch function found in + * llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp + * The code was licensed under Apache License v2.0 with LLVM Exceptions + */ +bool TemplateMatch(const char* templ, const char* str) +{ + if ((!str) || str[0] == 0) + return false; + bool start = false; + if (templ && templ[0] == '^') { + start = true; + templ++; + } + bool asterisk = false; + while (templ && templ[0]) { + if (templ[0] == '*') { + templ++; + start = false; + asterisk = true; + continue; + } + if (templ[0] == '$') + return str[0] == 0 || asterisk; + if (str[0] == 0) + return false; + char* tpos = (char*)strchr(templ, '*'); + char* tpos1 = (char*)strchr(templ, '$'); + if ((!tpos) || (tpos1 && tpos1 < tpos)) + tpos = tpos1; + if (tpos) + tpos[0] = 0; + const char* str0 = str; + const char* spos = strstr(str, templ); + str = spos + strlen(templ); + templ = tpos; + if (tpos) + tpos[0] = tpos == tpos1 ? '$' : '*'; + if (!spos) + return false; + if (start && spos != str0) + return false; + start = false; + asterisk = false; + } + return true; +} +} + +std::string parseSuppression(std::string line) +{ + boost::trim(line, std::locale::classic()); + if (line.empty() || line[0] == '#') { + // comment + return {}; + } else if (line.compare(0, 5, "leak:") == 0) { + return line.substr(5); + } + std::cerr << "invalid suppression line: " << line << '\n'; + return {}; +} + +std::vector parseSuppressions(const std::string& suppressionFile, bool* ok) +{ + if (ok) { + *ok = true; + } + + if (suppressionFile.empty()) { + return {}; + } + + auto stream = std::ifstream(suppressionFile); + if (!stream.is_open()) { + std::cerr << "failed to open suppression file: " << suppressionFile << '\n'; + if (ok) { + *ok = false; + } + return {}; + } + + return parseSuppressionsFile(stream); +} + +bool matchesSuppression(const std::string& suppression, const std::string& haystack) +{ + return suppression == haystack || TemplateMatch(suppression.c_str(), haystack.c_str()); +} + +std::vector builtinSuppressions() +{ + return { + // libc + {"__nss_module_allocate", 0, 0}, + {"__gconv_read_conf", 0, 0}, + {"__new_exitfn", 0, 0}, + {"tzset_internal", 0, 0}, + // dynamic linker + {"dl_open_worker", 0, 0}, + // glib event loop + {"g_main_context_new", 0, 0}, + {"g_main_context_new", 0, 0}, + {"g_thread_self", 0, 0}, + }; +} diff --git a/src/analyze/suppressions.h b/src/analyze/suppressions.h new file mode 100644 index 00000000..bc6d2641 --- /dev/null +++ b/src/analyze/suppressions.h @@ -0,0 +1,26 @@ +/* + SPDX-FileCopyrightText: 2021 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#ifndef SUPPRESSIONS_H +#define SUPPRESSIONS_H + +#include +#include + +std::string parseSuppression(std::string line); +std::vector parseSuppressions(const std::string& suppressionFile, bool* ok); +bool matchesSuppression(const std::string& suppression, const std::string& haystack); + +struct Suppression +{ + std::string pattern; + int64_t matches = 0; + int64_t leaked = 0; +}; + +std::vector builtinSuppressions(); + +#endif // SUPPRESSIONS_H diff --git a/src/interpret/CMakeLists.txt b/src/interpret/CMakeLists.txt index 6a72b794..f6f5cc77 100644 --- a/src/interpret/CMakeLists.txt +++ b/src/interpret/CMakeLists.txt @@ -2,8 +2,9 @@ if (ECM_FOUND) include(ECMEnableSanitizers) endif() +find_package(Elfutils 0.158 REQUIRED) + include_directories( - ${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/3rdparty/ ) @@ -11,10 +12,16 @@ add_definitions("-DHAVE_STDINT_H") add_executable(heaptrack_interpret heaptrack_interpret.cpp + dwarfdiecache.cpp + symbolcache.cpp ) target_link_libraries(heaptrack_interpret - backtrace + PRIVATE ${LIBDW_LIBRARIES} tsl::robin_map +) + +target_include_directories(heaptrack_interpret + PRIVATE ${LIBDW_INCLUDE_DIRS} ) install(TARGETS heaptrack_interpret diff --git a/src/interpret/dwarfdiecache.cpp b/src/interpret/dwarfdiecache.cpp new file mode 100644 index 00000000..21363ef6 --- /dev/null +++ b/src/interpret/dwarfdiecache.cpp @@ -0,0 +1,376 @@ +/* + dwarfdiecache.cpp + + SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "dwarfdiecache.h" + +#include + +#include + +#include + +namespace { +enum class WalkResult +{ + Recurse, + Skip, + Return +}; +template +WalkResult walkDieTree(const Callback& callback, Dwarf_Die* die) +{ + auto result = callback(die); + if (result != WalkResult::Recurse) + return result; + + Dwarf_Die childDie; + if (dwarf_child(die, &childDie) == 0) { + result = walkDieTree(callback, &childDie); + if (result == WalkResult::Return) + return result; + + Dwarf_Die siblingDie; + while (dwarf_siblingof(&childDie, &siblingDie) == 0) { + result = walkDieTree(callback, &siblingDie); + if (result == WalkResult::Return) + return result; + childDie = siblingDie; + } + } + return WalkResult::Skip; +} + +template +void walkRanges(const Callback& callback, Dwarf_Die* die) +{ + Dwarf_Addr low = 0; + Dwarf_Addr high = 0; + Dwarf_Addr base = 0; + ptrdiff_t rangeOffset = 0; + while ((rangeOffset = dwarf_ranges(die, rangeOffset, &base, &low, &high)) > 0) { + if (!callback(DwarfRange {low, high})) + return; + } +} + +// see libdw_visit_scopes.c in elfutils +bool mayHaveScopes(Dwarf_Die* die) +{ + switch (dwarf_tag(die)) { + /* DIEs with addresses we can try to match. */ + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_lexical_block: + case DW_TAG_with_stmt: + case DW_TAG_catch_block: + case DW_TAG_try_block: + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + return true; + + /* DIEs without addresses that can own DIEs with addresses. */ + case DW_TAG_namespace: + case DW_TAG_class_type: + case DW_TAG_structure_type: + return true; + + /* Other DIEs we have no reason to descend. */ + default: + break; + } + return false; +} + +bool dieContainsAddress(Dwarf_Die* die, Dwarf_Addr address) +{ + bool contained = false; + walkRanges( + [&contained, address](DwarfRange range) { + if (range.contains(address)) { + contained = true; + return false; + } + return true; + }, + die); + return contained; +} +} + +const char* linkageName(Dwarf_Die* die) +{ + Dwarf_Attribute attr; + Dwarf_Attribute* result = dwarf_attr_integrate(die, DW_AT_MIPS_linkage_name, &attr); + if (!result) + result = dwarf_attr_integrate(die, DW_AT_linkage_name, &attr); + + return result ? dwarf_formstring(result) : nullptr; +} + +Dwarf_Die* specificationDie(Dwarf_Die* die, Dwarf_Die* dieMem) +{ + Dwarf_Attribute attr; + if (dwarf_attr_integrate(die, DW_AT_specification, &attr)) + return dwarf_formref_die(&attr, dieMem); + return nullptr; +} + +/// prepend the names of all scopes that reference the @p die to @p name +void prependScopeNames(std::string& name, Dwarf_Die* die, tsl::robin_map& cache) +{ + Dwarf_Die dieMem; + Dwarf_Die* scopes = nullptr; + auto nscopes = dwarf_getscopes_die(die, &scopes); + + struct ScopesToCache + { + Dwarf_Off offset; + std::size_t trailing; + }; + std::vector cacheOps; + + // skip scope for the die itself at the start and the compile unit DIE at end + for (int i = 1; i < nscopes - 1; ++i) { + auto scope = scopes + i; + + const auto scopeOffset = dwarf_dieoffset(scope); + + auto it = cache.find(scopeOffset); + if (it != cache.end()) { + name.insert(0, "::"); + name.insert(0, it->second); + // we can stop, cached names are always fully qualified + break; + } + + if (auto scopeLinkageName = linkageName(scope)) { + // prepend the fully qualified linkage name + name.insert(0, "::"); + cacheOps.push_back({scopeOffset, name.size()}); + // we have to demangle the scope linkage name, otherwise we get a + // mish-mash of mangled and non-mangled names + name.insert(0, demangle(scopeLinkageName)); + // we can stop now, the scope is fully qualified + break; + } + + if (auto scopeName = dwarf_diename(scope)) { + // prepend this scope's name, e.g. the class or namespace name + name.insert(0, "::"); + cacheOps.push_back({scopeOffset, name.size()}); + name.insert(0, scopeName); + } + + if (auto specification = specificationDie(scope, &dieMem)) { + free(scopes); + scopes = nullptr; + cacheOps.push_back({scopeOffset, name.size()}); + cacheOps.push_back({dwarf_dieoffset(specification), name.size()}); + // follow the scope's specification DIE instead + prependScopeNames(name, specification, cache); + break; + } + } + + for (const auto& cacheOp : cacheOps) + cache[cacheOp.offset] = name.substr(0, name.size() - cacheOp.trailing); + + free(scopes); +} + +bool operator==(const Dwarf_Die& lhs, const Dwarf_Die& rhs) +{ + return lhs.addr == rhs.addr && lhs.cu == rhs.cu && lhs.abbrev == rhs.abbrev; +} + +std::string qualifiedDieName(Dwarf_Die* die, tsl::robin_map& cache) +{ + // linkage names are fully qualified, meaning we can stop early then + if (auto name = linkageName(die)) + return name; + + // otherwise do a more complex lookup that includes namespaces and other context information + // this is important for inlined subroutines such as lambdas or std:: algorithms + std::string name; + if (auto dieName = dwarf_diename(die)) + name = dieName; + + // use the specification DIE which is within the DW_TAG_namespace + Dwarf_Die dieMem; + if (auto specification = specificationDie(die, &dieMem)) + die = specification; + + prependScopeNames(name, die, cache); + + return name; +} + +std::string demangle(const std::string& mangledName) +{ + if (mangledName.length() < 3) { + return mangledName; + } else { + static size_t demangleBufferLength = 1024; + static char* demangleBuffer = reinterpret_cast(malloc(demangleBufferLength)); + + // Require GNU v3 ABI by the "_Z" prefix. + if (mangledName[0] == '_' && mangledName[1] == 'Z') { + int status = -1; + char* dsymname = abi::__cxa_demangle(mangledName.data(), demangleBuffer, &demangleBufferLength, &status); + if (status == 0 && dsymname) + return demangleBuffer = dsymname; + } + } + return mangledName; +} + +std::string absoluteSourcePath(const char* path, Dwarf_Die* cuDie) +{ + if (!path || !cuDie || path[0] == '/') + return path; + + Dwarf_Attribute attr; + auto compDir = dwarf_formstring(dwarf_attr(cuDie, DW_AT_comp_dir, &attr)); + if (!compDir) + return path; + + std::string ret; + ret.reserve(static_cast(strlen(compDir) + strlen(path) + 1)); + ret.append(compDir); + ret.append("/"); + ret.append(path); + return ret; +} + +SourceLocation callSourceLocation(Dwarf_Die* die, Dwarf_Files* files, Dwarf_Die* cuDie) +{ + SourceLocation ret; + + Dwarf_Attribute attr; + Dwarf_Word val = 0; + + const auto hasCallFile = dwarf_formudata(dwarf_attr(die, DW_AT_call_file, &attr), &val) == 0; + if (hasCallFile) { + ret.file = absoluteSourcePath(dwarf_filesrc(files, val, nullptr, nullptr), cuDie); + } + + const auto hasCallLine = dwarf_formudata(dwarf_attr(die, DW_AT_call_line, &attr), &val) == 0; + if (hasCallLine) { + ret.line = static_cast(val); + } + + return ret; +} + +std::vector findInlineScopes(Dwarf_Die* subprogram, Dwarf_Addr offset) +{ + std::vector scopes; + walkDieTree( + [offset, &scopes](Dwarf_Die* die) { + if (dwarf_tag(die) != DW_TAG_inlined_subroutine) + return WalkResult::Recurse; + if (dieContainsAddress(die, offset)) { + scopes.push_back(*die); + return WalkResult::Recurse; + } + return WalkResult::Skip; + }, + subprogram); + return scopes; +} + +SubProgramDie::SubProgramDie(Dwarf_Die die) + : m_ranges {die, {}} +{ + walkRanges( + [this](DwarfRange range) { + m_ranges.ranges.push_back(range); + return true; + }, + &die); +} + +CuDieRangeMapping::CuDieRangeMapping(Dwarf_Die cudie, Dwarf_Addr bias) + : m_bias {bias} + , m_cuDieRanges {cudie, {}} +{ + walkRanges( + [this, bias](DwarfRange range) { + m_cuDieRanges.ranges.push_back({range.low + bias, range.high + bias}); + return true; + }, + &cudie); +} + +SubProgramDie* CuDieRangeMapping::findSubprogramDie(Dwarf_Addr offset) +{ + if (m_subPrograms.empty()) + addSubprograms(); + + auto it = std::find_if(m_subPrograms.begin(), m_subPrograms.end(), + [offset](const SubProgramDie& program) { return program.contains(offset); }); + if (it == m_subPrograms.end()) + return nullptr; + + return &(*it); +} + +void CuDieRangeMapping::addSubprograms() +{ + walkDieTree( + [this](Dwarf_Die* die) { + if (!mayHaveScopes(die)) + return WalkResult::Skip; + + if (dwarf_tag(die) == DW_TAG_subprogram) { + SubProgramDie program(*die); + if (!program.isEmpty()) + m_subPrograms.push_back(program); + + return WalkResult::Skip; + } + return WalkResult::Recurse; + }, + cudie()); +} + +const std::string& CuDieRangeMapping::dieName(Dwarf_Die* die) +{ + const auto offset = dwarf_dieoffset(die); + auto it = m_dieNameCache.find(offset); + if (it == m_dieNameCache.end()) + it = m_dieNameCache.insert({offset, demangle(qualifiedDieName(die, m_dieNameCache))}).first; + + return it->second; +} + +DwarfDieCache::DwarfDieCache(Dwfl_Module* mod) +{ + if (!mod) + return; + + Dwarf_Die* die = nullptr; + Dwarf_Addr bias = 0; + while ((die = dwfl_module_nextcu(mod, die, &bias))) { + CuDieRangeMapping cuDieMapping(*die, bias); + if (!cuDieMapping.isEmpty()) + m_cuDieRanges.push_back(cuDieMapping); + } +} + +CuDieRangeMapping* DwarfDieCache::findCuDie(Dwarf_Addr addr) +{ + auto it = std::find_if(m_cuDieRanges.begin(), m_cuDieRanges.end(), + [addr](const CuDieRangeMapping& cuDieMapping) { return cuDieMapping.contains(addr); }); + if (it == m_cuDieRanges.end()) + return nullptr; + + return &(*it); +} diff --git a/src/interpret/dwarfdiecache.h b/src/interpret/dwarfdiecache.h new file mode 100644 index 00000000..f3885860 --- /dev/null +++ b/src/interpret/dwarfdiecache.h @@ -0,0 +1,147 @@ +/* + dwarfdiecache.h + + SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef DWARFDIECACHE_H +#define DWARFDIECACHE_H + +#include + +#include + +#include +#include +#include + +/// @return the demangled symbol name +std::string demangle(const std::string& mangledName); + +/// @return the absolute source path for the potential @p path in the given @p cuDie +std::string absoluteSourcePath(const char* path, Dwarf_Die* cuDie); + +struct SourceLocation +{ + std::string file; + int line = 0; +}; + +/// @return the file and line location encoded in the DW_AT_call_{file,line} data of @p die +SourceLocation callSourceLocation(Dwarf_Die* die, Dwarf_Files* files, Dwarf_Die* cuDie); + +struct DwarfRange +{ + Dwarf_Addr low; + Dwarf_Addr high; + + bool contains(Dwarf_Addr addr) const + { + return low <= addr && addr < high; + } +}; + +/// cache of dwarf ranges for a given Dwarf_Die +struct DieRanges +{ + Dwarf_Die die; + std::vector ranges; + + bool contains(Dwarf_Addr addr) const + { + return std::any_of(ranges.begin(), ranges.end(), + [addr](const DwarfRange& range) { return range.contains(addr); }); + } +}; + +/// cache of sub program DIE, its ranges and the accompanying die name +class SubProgramDie +{ +public: + SubProgramDie(Dwarf_Die die); + + bool isEmpty() const + { + return m_ranges.ranges.empty(); + } + /// @p offset a bias-corrected offset + bool contains(Dwarf_Addr offset) const + { + return m_ranges.contains(offset); + } + Dwarf_Die* die() + { + return &m_ranges.die; + } + +private: + DieRanges m_ranges; +}; + +/// cache of dwarf ranges for a CU DIE and child sub programs +class CuDieRangeMapping +{ +public: + CuDieRangeMapping(Dwarf_Die cudie, Dwarf_Addr bias); + + bool isEmpty() const + { + return m_cuDieRanges.ranges.empty(); + } + bool contains(Dwarf_Addr addr) const + { + return m_cuDieRanges.contains(addr); + } + Dwarf_Addr bias() + { + return m_bias; + } + Dwarf_Die* cudie() + { + return &m_cuDieRanges.die; + } + + /// On first call this will visit the CU DIE to cache all subprograms + /// @return the DW_TAG_subprogram DIE that contains @p offset + /// @p offset a bias-corrected address to find a subprogram for + SubProgramDie* findSubprogramDie(Dwarf_Addr offset); + + /// @return a fully qualified, demangled symbol name for @p die + const std::string& dieName(Dwarf_Die* die); + +private: + void addSubprograms(); + + Dwarf_Addr m_bias = 0; + DieRanges m_cuDieRanges; + std::vector m_subPrograms; + tsl::robin_map m_dieNameCache; +}; + +/** + * @return all DW_TAG_inlined_subroutine DIEs that contain @p offset + * @p subprogram DIE sub tree that should be traversed to look for inlined scopes + * @p offset bias-corrected address that is checked against the dwarf ranges of the DIEs + */ +std::vector findInlineScopes(Dwarf_Die* subprogram, Dwarf_Addr offset); + +/** + * This cache makes it easily possible to find a CU DIE (i.e. Compilation Unit Debugging Information Entry) + * based on a + */ +class DwarfDieCache +{ +public: + DwarfDieCache(Dwfl_Module* mod = nullptr); + + /// @p addr absolute address, not bias-corrected + CuDieRangeMapping* findCuDie(Dwarf_Addr addr); + +public: + std::vector m_cuDieRanges; +}; + +#endif // DWARFDIECACHE_H diff --git a/src/interpret/heaptrack_interpret.cpp b/src/interpret/heaptrack_interpret.cpp index 2fbfb637..48ec9608 100644 --- a/src/interpret/heaptrack_interpret.cpp +++ b/src/interpret/heaptrack_interpret.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2022 Milian Wolff + + SPDX-License-Identifier: GPL-2.0-or-later +*/ /** * @file heaptrack_interpret.cpp @@ -29,45 +17,67 @@ #ifdef __linux__ #include #endif +#include #include -#include #include -#include - -#include +#include "dwarfdiecache.h" +#include "symbolcache.h" -#include "libbacktrace/backtrace.h" -#include "libbacktrace/internal.h" #include "util/linereader.h" #include "util/linewriter.h" #include "util/pointermap.h" -#include +#include +#include + +#include #include using namespace std; namespace { +bool isArmArch() +{ +#ifdef __arm__ + return true; +#else + return false; +#endif +} #define error_out cerr << __FILE__ << ':' << __LINE__ << " ERROR:" -string demangle(const char* function) +bool startsWith(const std::string& haystack, const char* needle) { - if (!function) { - return {}; - } else if (function[0] != '_' || function[1] != 'Z') { - return {function}; - } + return haystack.compare(0, strlen(needle), needle) == 0; +} - string ret; - int status = 0; - char* demangled = abi::__cxa_demangle(function, 0, 0, &status); - if (demangled) { - ret = demangled; - free(demangled); +static uint64_t alignedAddress(uint64_t addr, bool isArmArch) +{ + // Adjust addr back. The symtab entries are 1 off for all practical purposes. + return (isArmArch && (addr & 1)) ? addr - 1 : addr; +} + +static SymbolCache::Symbols extractSymbols(Dwfl_Module* module, uint64_t elfStart, bool isArmArch) +{ + SymbolCache::Symbols symbols; + + const auto numSymbols = dwfl_module_getsymtab(module); + if (numSymbols <= 0) + return symbols; + + symbols.reserve(numSymbols); + for (int i = 0; i < numSymbols; ++i) { + GElf_Sym sym; + GElf_Addr symAddr; + const auto symbol = dwfl_module_getsym_info(module, i, &sym, &symAddr, nullptr, nullptr, nullptr); + if (symbol) { + const uint64_t start = alignedAddress(sym.st_value, isArmArch); + symbols.push_back({symAddr - elfStart, start, sym.st_size, symbol}); + } } - return ret; + return symbols; } struct Frame @@ -115,83 +125,138 @@ struct ResolvedIP vector inlined; }; -struct Module +struct ModuleFragment { - Module(string fileName, uintptr_t addressStart, uintptr_t addressEnd, backtrace_state* backtraceState, - size_t moduleIndex) + ModuleFragment(string fileName, uintptr_t addressStart, uintptr_t fragmentStart, uintptr_t fragmentEnd, + size_t moduleIndex) : fileName(fileName) , addressStart(addressStart) - , addressEnd(addressEnd) + , fragmentStart(fragmentStart) + , fragmentEnd(fragmentEnd) , moduleIndex(moduleIndex) - , backtraceState(backtraceState) + { + } + + bool operator<(const ModuleFragment& module) const + { + return tie(addressStart, fragmentStart, fragmentEnd, moduleIndex) + < tie(module.addressStart, module.fragmentStart, module.fragmentEnd, module.moduleIndex); + } + + bool operator!=(const ModuleFragment& module) const + { + return tie(addressStart, fragmentStart, fragmentEnd, moduleIndex) + != tie(module.addressStart, module.fragmentStart, module.fragmentEnd, module.moduleIndex); + } + + string fileName; + uintptr_t addressStart; + uintptr_t fragmentStart; + uintptr_t fragmentEnd; + size_t moduleIndex; +}; + +struct Module +{ + Module(string fileName, uintptr_t addressStart, Dwfl_Module* module, SymbolCache* symbolCache) + : fileName(std::move(fileName)) + , addressStart(addressStart) + , module(module) + , dieCache(module) + , symbolCache(symbolCache) + { + } + + Module() + : Module({}, 0, nullptr, nullptr) { } AddressInformation resolveAddress(uintptr_t address) const { AddressInformation info; - if (!backtraceState) { + + if (!module) { return info; } - // try to find frame information from debug information - backtrace_pcinfo(backtraceState, address, - [](void* data, uintptr_t /*addr*/, const char* file, int line, const char* function) -> int { - Frame frame(demangle(function), file ? file : "", line); - auto info = reinterpret_cast(data); - if (!info->frame.isValid()) { - info->frame = frame; - } else { - info->inlined.push_back(frame); - } - return 0; - }, - [](void* /*data*/, const char* /*msg*/, int /*errnum*/) {}, &info); - - // no debug information available? try to fallback on the symbol table information - if (!info.frame.isValid()) { - struct Data - { - AddressInformation* info; - const Module* module; - uintptr_t address; - }; - Data data = {&info, this, address}; - backtrace_syminfo( - backtraceState, address, - [](void* data, uintptr_t /*pc*/, const char* symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) { - if (symname) { - reinterpret_cast(data)->info->frame.function = demangle(symname); - } - }, - [](void* _data, const char* msg, int errnum) { - auto* data = reinterpret_cast(_data); - error_out << "Module backtrace error for address " << hex << data->address << dec << " in module " - << data->module->fileName << " (code " << errnum << "): " << msg << endl; - }, - &data); + if (!symbolCache->hasSymbols(fileName)) { + // cache all symbols in a sorted lookup table and demangle them on-demand + // note that the symbols within the symtab aren't necessarily sorted, + // which makes searching repeatedly via dwfl_module_addrinfo potentially very slow + symbolCache->setSymbols(fileName, extractSymbols(module, addressStart, isArmArch())); } - return info; - } + auto cachedAddrInfo = symbolCache->findSymbol(fileName, address - addressStart); + if (cachedAddrInfo.isValid()) { + info.frame.function = std::move(cachedAddrInfo.symname); + } - bool operator<(const Module& module) const - { - return tie(addressStart, addressEnd, moduleIndex) - < tie(module.addressStart, module.addressEnd, module.moduleIndex); - } + auto cuDie = dieCache.findCuDie(address); + if (!cuDie) { + return info; + } - bool operator!=(const Module& module) const - { - return tie(addressStart, addressEnd, moduleIndex) - != tie(module.addressStart, module.addressEnd, module.moduleIndex); + const auto offset = address - cuDie->bias(); + auto srcloc = dwarf_getsrc_die(cuDie->cudie(), offset); + if (srcloc) { + const char* srcfile = dwarf_linesrc(srcloc, nullptr, nullptr); + if (srcfile) { + const auto file = std::string(srcfile); + info.frame.file = srcfile; + dwarf_lineno(srcloc, &info.frame.line); + } + } + + auto* subprogram = cuDie->findSubprogramDie(offset); + if (!subprogram) { + return info; + } + + // resolve the inline chain if possible + auto scopes = findInlineScopes(subprogram->die(), offset); + + if (scopes.empty()) { + // no inline frames, use subprogram name directly and return + info.frame.function = cuDie->dieName(subprogram->die()); + return info; + } + + // use name of the last inlined function as symbol + info.frame.function = cuDie->dieName(&scopes.back()); + + Dwarf_Files* files = nullptr; + dwarf_getsrcfiles(cuDie->cudie(), &files, nullptr); + + auto handleDie = [&](Dwarf_Die *scope, Dwarf_Die *prevScope) { + const auto tag = dwarf_tag(prevScope); + if (tag != DW_TAG_inlined_subroutine) { + error_out << "unexpected prev scope tag: " << std::hex << tag << '\n'; + return; + } + + auto call = callSourceLocation(prevScope, files, cuDie->cudie()); + info.inlined.push_back({cuDie->dieName(scope), std::move(call.file), call.line}); + }; + + // iterate in reverse, to properly rebuild the inline stack + // note that we need to take the DW_AT_call_{file,line} from the previous scope DIE + const auto numScopes = scopes.size(); + for (std::size_t scopeIndex = numScopes - 1; scopeIndex >= 1; --scopeIndex) { + handleDie(&scopes[scopeIndex - 1], &scopes[scopeIndex]); + } + + // the very last frame is the one where all the code got inlined into + handleDie(subprogram->die(), &scopes.front()); + + return info; } string fileName; uintptr_t addressStart; - uintptr_t addressEnd; - size_t moduleIndex; - backtrace_state* backtraceState; + Dwfl_Module* module; + mutable DwarfDieCache dieCache; + SymbolCache* symbolCache; }; struct AccumulatedTraceData @@ -199,62 +264,90 @@ struct AccumulatedTraceData AccumulatedTraceData() : out(fileno(stdout)) { - m_modules.reserve(256); - m_backtraceStates.reserve(64); + m_moduleFragments.reserve(256); m_internedData.reserve(4096); m_encounteredIps.reserve(32768); + + { + std::string debugPath(":.debug:/usr/lib/debug"); + const auto length = debugPath.size() + 1; + m_debugPath = new char[length]; + std::memcpy(m_debugPath, debugPath.data(), length); + } + + m_callbacks = { + &dwfl_build_id_find_elf, + &dwfl_standard_find_debuginfo, + &dwfl_offline_section_address, + &m_debugPath, + }; + + m_dwfl = dwfl_begin(&m_callbacks); } ~AccumulatedTraceData() { out.write("# strings: %zu\n# ips: %zu\n", m_internedData.size(), m_encounteredIps.size()); out.flush(); + + delete[] m_debugPath; + dwfl_end(m_dwfl); } ResolvedIP resolve(const uintptr_t ip) { if (m_modulesDirty) { // sort by addresses, required for binary search below - sort(m_modules.begin(), m_modules.end()); + sort(m_moduleFragments.begin(), m_moduleFragments.end()); #ifndef NDEBUG - for (size_t i = 0; i < m_modules.size(); ++i) { - const auto& m1 = m_modules[i]; - for (size_t j = i + 1; j < m_modules.size(); ++j) { + for (size_t i = 0; i < m_moduleFragments.size(); ++i) { + const auto& m1 = m_moduleFragments[i]; + for (size_t j = i + 1; j < m_moduleFragments.size(); ++j) { if (i == j) { continue; } - const auto& m2 = m_modules[j]; - if ((m1.addressStart <= m2.addressStart && m1.addressEnd > m2.addressStart) - || (m1.addressStart < m2.addressEnd && m1.addressEnd >= m2.addressEnd)) { - cerr << "OVERLAPPING MODULES: " << hex << m1.moduleIndex << " (" << m1.addressStart << " to " - << m1.addressEnd << ") and " << m1.moduleIndex << " (" << m2.addressStart << " to " - << m2.addressEnd << ")\n" + const auto& m2 = m_moduleFragments[j]; + if ((m1.fragmentStart <= m2.fragmentStart && m1.fragmentEnd > m2.fragmentStart) + || (m1.fragmentStart < m2.fragmentEnd && m1.fragmentEnd >= m2.fragmentEnd)) { + cerr << "OVERLAPPING MODULES: " << hex << m1.moduleIndex << " (" << m1.fragmentStart << " to " + << m1.fragmentEnd << ") and " << m1.moduleIndex << " (" << m2.fragmentStart << " to " + << m2.fragmentEnd << ")\n" << dec; - } else if (m2.addressStart >= m1.addressEnd) { + } else if (m2.fragmentStart >= m1.fragmentEnd) { break; } } } #endif + // reset dwfl state + m_modules.clear(); + + dwfl_report_begin(m_dwfl); + dwfl_report_end(m_dwfl, nullptr, nullptr); + m_modulesDirty = false; } auto resolveFrame = [this](const Frame& frame) { - return ResolvedFrame{intern(frame.function), intern(frame.file), frame.line}; + return ResolvedFrame {intern(frame.function), intern(frame.file), frame.line}; }; ResolvedIP data; // find module for this instruction pointer - auto module = - lower_bound(m_modules.begin(), m_modules.end(), ip, - [](const Module& module, const uintptr_t ip) -> bool { return module.addressEnd < ip; }); - if (module != m_modules.end() && module->addressStart <= ip && module->addressEnd >= ip) { - data.moduleIndex = module->moduleIndex; - const auto info = module->resolveAddress(ip); - data.frame = resolveFrame(info.frame); - std::transform(info.inlined.begin(), info.inlined.end(), std::back_inserter(data.inlined), resolveFrame); + auto fragment = lower_bound( + m_moduleFragments.begin(), m_moduleFragments.end(), ip, + [](const ModuleFragment& fragment, const uintptr_t ip) -> bool { return fragment.fragmentEnd < ip; }); + if (fragment != m_moduleFragments.end() && fragment->fragmentStart <= ip && fragment->fragmentEnd >= ip) { + data.moduleIndex = fragment->moduleIndex; + + if (auto module = reportModule(*fragment)) { + const auto info = module->resolveAddress(ip); + data.frame = resolveFrame(info.frame); + std::transform(info.inlined.begin(), info.inlined.end(), std::back_inserter(data.inlined), + resolveFrame); + } } return data; } @@ -265,35 +358,33 @@ struct AccumulatedTraceData return 0; } - auto it = m_internedData.find(str); - if (it != m_internedData.end()) { - if (internedString) { - *internedString = it->first.data(); - } - return it->second; - } const size_t id = m_internedData.size() + 1; - it = m_internedData.insert(it, make_pair(str, id)); + auto inserted = m_internedData.insert({str, id}); if (internedString) { - *internedString = it->first.data(); + *internedString = inserted.first->first.data(); } + + if (!inserted.second) { + return inserted.first->second; + } + out.write("s "); out.write(str); out.write("\n"); return id; } - void addModule(string fileName, backtrace_state* backtraceState, const size_t moduleIndex, - const uintptr_t addressStart, const uintptr_t addressEnd) + void addModule(string fileName, const size_t moduleIndex, const uintptr_t addressStart, + const uintptr_t fragmentStart, const uintptr_t fragmentEnd) { - m_modules.emplace_back(fileName, addressStart, addressEnd, backtraceState, moduleIndex); + m_moduleFragments.emplace_back(fileName, addressStart, fragmentStart, fragmentEnd, moduleIndex); m_modulesDirty = true; } void clearModules() { // TODO: optimize this, reuse modules that are still valid - m_modules.clear(); + m_moduleFragments.clear(); m_modulesDirty = true; } @@ -303,13 +394,11 @@ struct AccumulatedTraceData return 0; } - auto it = m_encounteredIps.find(instructionPointer); - if (it != m_encounteredIps.end()) { - return it->second; - } - const size_t ipId = m_encounteredIps.size() + 1; - m_encounteredIps.insert(it, make_pair(instructionPointer, ipId)); + auto inserted = m_encounteredIps.insert({instructionPointer, ipId}); + if (!inserted.second) { + return inserted.first->second; + } const auto ip = resolve(instructionPointer); out.write("i %zx %zx", instructionPointer, ip.moduleIndex); @@ -326,66 +415,47 @@ struct AccumulatedTraceData return ipId; } - /** - * Prevent the same file from being initialized multiple times. - * This drastically cuts the memory consumption down - */ - backtrace_state* findBacktraceState(const char* fileName, uintptr_t addressStart) + LineWriter out; + +private: + Module* reportModule(const ModuleFragment& module) { - if (boost::algorithm::starts_with(fileName, "linux-vdso.so")) { - // prevent warning, since this will always fail + if (startsWith(module.fileName, "linux-vdso.so")) { return nullptr; } - auto it = m_backtraceStates.find(fileName); - if (it != m_backtraceStates.end()) { - return it->second; - } - - struct CallbackData - { - const char* fileName; - }; - CallbackData data = {fileName}; - - auto errorHandler = [](void* rawData, const char* msg, int errnum) { - auto data = reinterpret_cast(rawData); - error_out << "Failed to create backtrace state for module " << data->fileName << ": " << msg << " / " - << strerror(errnum) << " (error code " << errnum << ")" << endl; - }; - - auto state = backtrace_create_state(data.fileName, /* we are single threaded, so: not thread safe */ false, - errorHandler, &data); - - if (state) { - const int descriptor = backtrace_open(data.fileName, errorHandler, &data, nullptr); - if (descriptor >= 1) { - int foundSym = 0; - int foundDwarf = 0; - auto ret = elf_add(state, data.fileName, descriptor, addressStart, errorHandler, &data, - &state->fileline_fn, &foundSym, &foundDwarf, false, false); - if (ret && foundSym) { - state->syminfo_fn = &elf_syminfo; - } else { - state->syminfo_fn = &elf_nosyms; - } + auto& ret = m_modules[module.fileName]; + if (ret.module) + return &ret; + + auto dwflModule = dwfl_addrmodule(m_dwfl, module.addressStart); + if (!dwflModule) { + dwfl_report_begin_add(m_dwfl); + dwflModule = dwfl_report_elf(m_dwfl, module.fileName.c_str(), module.fileName.c_str(), -1, + module.addressStart, false); + dwfl_report_end(m_dwfl, nullptr, nullptr); + + if (!dwflModule) { + error_out << "Failed to report module for " << module.fileName << ": " << dwfl_errmsg(dwfl_errno()) + << endl; + return nullptr; } } - m_backtraceStates.insert(it, make_pair(fileName, state)); - - return state; + ret = Module(module.fileName, module.addressStart, dwflModule, &m_symbolCache); + return &ret; } - LineWriter out; - -private: - vector m_modules; - unordered_map m_backtraceStates; + vector m_moduleFragments; + Dwfl* m_dwfl = nullptr; + char* m_debugPath = nullptr; + Dwfl_Callbacks m_callbacks; + SymbolCache m_symbolCache; bool m_modulesDirty = false; - unordered_map m_internedData; - unordered_map m_encounteredIps; + tsl::robin_map m_internedData; + tsl::robin_map m_encounteredIps; + tsl::robin_map m_modules; }; struct Stats @@ -409,6 +479,26 @@ void exitHandler() int main(int /*argc*/, char** /*argv*/) { + [] { + // NOTE: we disable debuginfod by default as it can otherwise lead to + // nasty delays otherwise which are highly unexpected to users + // if desired, they can opt in to that via + // + // export HEAPTRACK_ENABLE_DEBUGINFOD=1 + if (!getenv("DEBUGINFOD_URLS")) { + return; + } + + auto enable = getenv("HEAPTRACK_ENABLE_DEBUGINFOD"); + if (!enable || !atoi(enable)) { + fprintf(stderr, + "NOTE: heaptrack detected DEBUGINFOD_URLS but will disable it to prevent \n" + "unintended network delays during recording\n" + "If you really want to use DEBUGINFOD, export HEAPTRACK_ENABLE_DEBUGINFOD=1\n"); + unsetenv("DEBUGINFOD_URLS"); + } + }(); + // optimize: we only have a single thread ios_base::sync_with_stdio(false); #ifdef __linux__ @@ -430,7 +520,16 @@ int main(int /*argc*/, char** /*argv*/) AllocationInfoSet allocationInfos; while (reader.getLine(cin)) { - if (reader.mode() == 'x') { + if (reader.mode() == 'v') { + unsigned int heaptrackVersion = 0; + reader >> heaptrackVersion; + unsigned int fileVersion = 0; + reader >> fileVersion; + if (fileVersion >= 3) { + reader.setExpectedSizedStrings(true); + } + data.out.write("%s\n", reader.line().c_str()); + } else if (reader.mode() == 'x') { if (!exe.empty()) { error_out << "received duplicate exe event - child process tracking is not yet supported" << endl; return 1; @@ -452,11 +551,11 @@ int main(int /*argc*/, char** /*argv*/) error_out << "failed to parse line: " << reader.line() << endl; return 1; } - auto state = data.findBacktraceState(internedString, addressStart); uintptr_t vAddr = 0; uintptr_t memSize = 0; while ((reader >> vAddr) && (reader >> memSize)) { - data.addModule(fileName, state, moduleIndex, addressStart + vAddr, addressStart + vAddr + memSize); + data.addModule(fileName, moduleIndex, addressStart, addressStart + vAddr, + addressStart + vAddr + memSize); } } } else if (reader.mode() == 't') { diff --git a/src/interpret/symbolcache.cpp b/src/interpret/symbolcache.cpp new file mode 100644 index 00000000..331c6410 --- /dev/null +++ b/src/interpret/symbolcache.cpp @@ -0,0 +1,81 @@ +/* + symbolcache.cpp + + SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "symbolcache.h" + +#include "dwarfdiecache.h" + +#include + +static bool operator<(const SymbolCache::SymbolCacheEntry& lhs, const SymbolCache::SymbolCacheEntry& rhs) +{ + return lhs.offset < rhs.offset; +} + +static bool operator==(const SymbolCache::SymbolCacheEntry& lhs, const SymbolCache::SymbolCacheEntry& rhs) +{ + return lhs.offset == rhs.offset && lhs.size == rhs.size; +} + +static bool operator<(const SymbolCache::SymbolCacheEntry& lhs, uint64_t addr) +{ + return lhs.offset < addr; +} + +bool SymbolCache::hasSymbols(const std::string& filePath) const +{ + return m_symbolCache.contains(filePath); +} + +SymbolCache::SymbolCacheEntry SymbolCache::findSymbol(const std::string& filePath, uint64_t relAddr) +{ + auto& symbols = m_symbolCache[filePath]; + auto it = std::lower_bound(symbols.begin(), symbols.end(), relAddr); + + // demangle symbols on demand instead of demangling all symbols directly + // hopefully most of the symbols we won't ever encounter after all + auto lazyDemangle = [](SymbolCache::SymbolCacheEntry& entry) { + if (!entry.demangled) { + entry.symname = demangle(entry.symname); + entry.demangled = true; + } + return entry; + }; + + if (it != symbols.end() && it->offset == relAddr) + return lazyDemangle(*it); + if (it == symbols.begin()) + return {}; + + --it; + + if (it->offset <= relAddr && (it->offset + it->size > relAddr || (it->size == 0))) { + return lazyDemangle(*it); + } + return {}; +} + +void SymbolCache::setSymbols(const std::string& filePath, Symbols symbols) +{ + /* + * use stable_sort to produce results that are comparable to what addr2line would + * return when we have entries like this in the symtab: + * + * 000000000045a130 l F .text 0000000000000033 .hidden __memmove_avx_unaligned + * 000000000045a180 l F .text 00000000000003d8 .hidden __memmove_avx_unaligned_erms + * 000000000045a180 l F .text 00000000000003d8 .hidden __memcpy_avx_unaligned_erms + * 000000000045a130 l F .text 0000000000000033 .hidden __memcpy_avx_unaligned + * + * here, addr2line would always find the first entry. we want to do the same + */ + + std::stable_sort(symbols.begin(), symbols.end()); + symbols.erase(std::unique(symbols.begin(), symbols.end()), symbols.end()); + m_symbolCache[filePath] = std::move(symbols); +} diff --git a/src/interpret/symbolcache.h b/src/interpret/symbolcache.h new file mode 100644 index 00000000..8c4331b5 --- /dev/null +++ b/src/interpret/symbolcache.h @@ -0,0 +1,58 @@ +/* + symbolcache.h + + SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB a KDAB Group company + SPDX-FileContributor: Milian Wolff + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef SYMBOLCACHE_H +#define SYMBOLCACHE_H + +#include + +#include +#include + +class SymbolCache +{ +public: + struct SymbolCacheEntry + { + SymbolCacheEntry(uint64_t offset = 0, uint64_t value = 0, uint64_t size = 0, const std::string& symname = {}) + : offset(offset) + , value(value) + , size(size) + , symname(symname) + { + } + + bool isValid() const + { + return !symname.empty(); + } + + // adjusted/absolute st_value, see documentation of the `addr` arg in `dwfl_module_getsym_info` + uint64_t offset; + // unadjusted/relative st_value + uint64_t value; + uint64_t size; + std::string symname; + bool demangled = false; + }; + using Symbols = std::vector; + + /// check if @c setSymbolCache was called for @p filePath already + bool hasSymbols(const std::string& filePath) const; + /// take @p cache, sort it and use it for symbol lookups in @p filePath + void setSymbols(const std::string& filePath, Symbols symbols); + /// find the symbol that encompasses @p relAddr in @p filePath + /// if the found symbol wasn't yet demangled, it will be demangled now + SymbolCacheEntry findSymbol(const std::string& filePath, uint64_t relAddr); + +private: + tsl::robin_map m_symbolCache; +}; + +#endif // SYMBOLCACHE_H diff --git a/src/track/CMakeLists.txt b/src/track/CMakeLists.txt index 438da01a..c7f9b372 100644 --- a/src/track/CMakeLists.txt +++ b/src/track/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( - ${Boost_INCLUDE_DIRS} -) - # heaptrack: bash script to inject/preload configure_file(heaptrack.sh.cmake ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/heaptrack @ONLY @@ -12,10 +8,9 @@ install(PROGRAMS ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}/heaptrack ) if (HEAPTRACK_USE_LIBUNWIND) - include_directories(${LIBUNWIND_INCLUDE_DIR}) - add_library(heaptrack_unwind STATIC trace_libunwind.cpp) - target_link_libraries(heaptrack_unwind LINK_PRIVATE ${LIBUNWIND_LIBRARY}) + target_include_directories(heaptrack_unwind PRIVATE ${LIBUNWIND_INCLUDE_DIRS}) + target_link_libraries(heaptrack_unwind PRIVATE ${LIBUNWIND_LIBRARIES}) else() add_library(heaptrack_unwind STATIC trace_unwind_tables.cpp) endif() @@ -26,6 +21,17 @@ endif() set_property(TARGET heaptrack_unwind PROPERTY POSITION_INDEPENDENT_CODE ON) +# heaptrack_env: runtime environment tests +add_executable(heaptrack_env heaptrack_env.cpp) + +install(TARGETS heaptrack_env + RUNTIME DESTINATION ${LIBEXEC_INSTALL_DIR} +) + +set_target_properties(heaptrack_env PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${LIBEXEC_INSTALL_DIR}" +) + # heaptrack_preload: track a newly started process add_library(heaptrack_preload MODULE heaptrack_preload.cpp @@ -56,12 +62,13 @@ add_library(heaptrack_inject MODULE libheaptrack.cpp ) -target_link_libraries(heaptrack_inject LINK_PRIVATE +target_link_libraries(heaptrack_inject PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${LIBUTIL_LIBRARY} heaptrack_unwind rt + tsl::robin_map ) set_target_properties(heaptrack_inject PROPERTIES diff --git a/src/track/heaptrack.sh.cmake b/src/track/heaptrack.sh.cmake index addd0970..b41bb3ba 100755 --- a/src/track/heaptrack.sh.cmake +++ b/src/track/heaptrack.sh.cmake @@ -1,25 +1,13 @@ #!/bin/sh # -# Copyright 2014-2017 Milian Wolff +# SPDX-FileCopyrightText: 2014-2021 Milian Wolff # -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# SPDX-License-Identifier: LGPL-2.1-or-later # usage() { - echo "Usage: $0 [--debug|-d] DEBUGGEE [ARGUMENT]..." + echo "Usage: $0 [--debug|-d] [--use-inject] [--record-only] DEBUGGEE [ARGUMENT]..." echo "or: $0 [--debug|-d] -p PID" echo "or: $0 -a FILE" echo @@ -47,12 +35,24 @@ usage() { echo " You are hereby warned, use it at your own risk!" echo echo "Optional arguments to heaptrack:" + echo " -r, --raw Only record raw data, do not interpret it." echo " -d, --debug Run the debuggee in GDB and heaptrack." + echo " --use-inject Use the same heaptrack_inject symbol interception mechanism instead of relying on" + echo " the dynamic linker and LD_PRELOAD. This is an experimental flag for now." + echo " --asan Enables running heaptrack on binaries built with gcc's address sanitizer enabled." + echo " Implies --use-inject." + echo " --record-only Only record and interpret the data, do not attempt to analyze it." echo " ARGUMENT Any number of arguments that will be passed verbatim" echo " to the debuggee." echo " -h, --help Show this help message and exit." echo " -v, --version Displays version information." echo " -o, --output Specifies the data-file for the captured data." + echo " %h in the file name string is replaced with the hostname of the system." + echo " %p in the file name string is replaced with the pid of the application being profiled." + echo " Parent directories will be created if output files are under non-existing directories." + echo " e.g.," + echo " ./%h/%p/outdat will be translated into .///outdat." + echo " The directory .// will be created if it doesn't exist." echo echo "Alternatively, to analyze a recorded heaptrack data file:" echo " -a, --analyze FILE Open the heaptrack data file in heaptrack_gui, if available," @@ -65,6 +65,11 @@ usage() { debug= pid= client= +use_inject_lib= +write_raw_data= +record_only= +asan= +asan_ld_preload= # path to current heaptrack.sh executable SCRIPT_PATH=$(readlink -f "$0") @@ -84,34 +89,59 @@ ORIG_CMDLINE=$@ while true; do case "$1" in "-d" | "--debug") - if [ -z "$(which gdb 2> /dev/null)" ]; then + if [ -z "$(command -v gdb 2> /dev/null)" ]; then echo "GDB is not installed, cannot debug heaptrack." exit 1 fi debug=1 shift 1 ;; + "--use-inject") + use_inject_lib=1 + shift 1 + ;; + "-r" | "--raw") + write_raw_data=1 + shift 1 + ;; + "--asan") + asan=1 + use_inject_lib=1 + shift 1 + ;; + "--record-only") + record_only=1 + shift 1 + ;; "-h" | "--help") usage exit 0 ;; - "-o" | "--output-file") + "-o" | "--output" | "--output-file") if [ -z "$2" ]; then echo "Missing output argument." exit 1 fi - output=$(readlink -f $2) + output=$(echo $2 | sed "s/%h/$(hostname)/g" | sed "s/%p/$$/g") if [ -d "$output" ]; then echo "Please specify a file-name or a full path-name for output." exit 1 fi + if [ ! -d $(dirname $output) ]; then + mkdir -p $(dirname $output) + fi + output=$(readlink -f $output) shift 2 ;; "-p" | "--pid") - if [ -z "$(which gdb 2> /dev/null)" ]; then + if [ -z "$(command -v gdb 2> /dev/null)" ]; then echo "GDB is not installed, cannot attach to running process." exit 1 fi + if [ -f "/proc/sys/kernel/yama/ptrace_scope" ] && [ "$(cat "/proc/sys/kernel/yama/ptrace_scope")" -gt "0" ]; then + echo "Cannot runtime-attach, you need to set /proc/sys/kernel/yama/ptrace_scope to 0" + exit 1 + fi pid=$2 if [ -z "$pid" ]; then echo "Missing PID argument." @@ -150,12 +180,22 @@ while true; do if [ "$1" = "--" ]; then shift 1 fi - if [ ! -x "$(which "$1" 2> /dev/null)" ]; then + if [ ! -x "$(command -v "$1" 2> /dev/null)" ]; then + if [ -z "$1" ] && [ -x "$EXE_PATH/heaptrack_gui" ]; then + "$EXE_PATH/heaptrack_gui" + exit + fi if [ -f "$1" ] && echo "$1" | grep -q "heaptrack."; then - openHeaptrackDataFiles $ORIG_CMDLINE + openHeaptrackDataFiles "$ORIG_CMDLINE" exit fi - echo "Error: Debuggee \"$1\" is not an executable." + + if [ ! -e "$1" ]; then + echo "Error: Debuggee \"$1\" was not found." + else + echo "Error: Debuggee \"$1\" is not an executable." + fi + echo echo "Usage: $0 [--debug|-d] [--help|-h] DEBUGGEE [ARGS...]" exit 1 @@ -176,14 +216,25 @@ fi LIB_REL_PATH="@LIB_REL_PATH@" LIBEXEC_REL_PATH="@LIBEXEC_REL_PATH@" +ENVCHECKER="$EXE_PATH/$LIBEXEC_REL_PATH/heaptrack_env" +if [ ! -f "$ENVCHECKER" ]; then + echo "Could not find heaptrack_env: $ENVCHECKER" + exit 1 +fi +ENVCHECKER=$(readlink -f "$ENVCHECKER") + INTERPRETER="$EXE_PATH/$LIBEXEC_REL_PATH/heaptrack_interpret" -if [ ! -f "$INTERPRETER" ]; then +if [ -z "$write_raw_data" ] && [ ! -f "$INTERPRETER" ]; then echo "Could not find heaptrack interpreter executable: $INTERPRETER" exit 1 fi INTERPRETER=$(readlink -f "$INTERPRETER") -LIBHEAPTRACK_PRELOAD="$EXE_PATH/$LIB_REL_PATH/libheaptrack_preload.so" +if [ -z "$use_inject_lib" ]; then + LIBHEAPTRACK_PRELOAD="$EXE_PATH/$LIB_REL_PATH/libheaptrack_preload.so" +else + LIBHEAPTRACK_PRELOAD="$EXE_PATH/$LIB_REL_PATH/libheaptrack_inject.so" +fi if [ ! -f "$LIBHEAPTRACK_PRELOAD" ]; then echo "Could not find heaptrack preload library $LIBHEAPTRACK_PRELOAD" exit 1 @@ -197,6 +248,16 @@ if [ ! -f "$LIBHEAPTRACK_INJECT" ]; then fi LIBHEAPTRACK_INJECT=$(readlink -f "$LIBHEAPTRACK_INJECT") +if [ -n "$asan" ]; then + asan_ld_preload=$(ldd $client | grep libasan | sed -e 's/.*=> //;s/ (.*//') + if [ -z "$asan_ld_preload" ]; then + echo "Unable to detect libasan when running ldd on the executable $client" + exit 1 + fi + echo "Found ASAN library: $asan_ld_preload" + asan_ld_preload="$asan_ld_preload:" +fi + # setup named pipe to read data from pipe=/tmp/heaptrack_fifo$$ mkfifo $pipe @@ -220,23 +281,36 @@ fi output_suffix="gz" COMPRESSOR="gzip -c" +UNCOMPRESSOR="gzip -dc" -if [ "@ZSTD_FOUND@" = "TRUE" ] && [ ! -z "$(which zstd 2> /dev/null)" ]; then +if [ "@ZSTD_FOUND@" = "TRUE" ] && [ ! -z "$(command -v zstd 2> /dev/null)" ]; then output_suffix="zst" COMPRESSOR="zstd -c" + UNCOMPRESSOR="zstd -dc" +fi + +output_non_raw="$output.$output_suffix" + +if [ ! -z "$write_raw_data" ]; then + output_suffix="raw.$output_suffix" fi # interpret the data and compress the output on the fly output="$output.$output_suffix" -"$INTERPRETER" < $pipe | $COMPRESSOR > "$output" & +if [ -z "$write_raw_data" ]; then + "$INTERPRETER" < $pipe | $COMPRESSOR > "$output" & +else + $COMPRESSOR < $pipe > "$output" & +fi debuggee=$! cleanup() { - if [ ! -z "$pid" ]; then + if [ ! -z "$pid" ] && [ -d "/proc/$pid" ]; then echo "removing heaptrack injection via GDB, this might take some time..." - gdb --batch-silent -n -iex="set auto-solib-add off" -p $pid \ + gdb --batch-silent -n -iex="set auto-solib-add off" \ + -iex="set language c" -p $pid \ --eval-command="sharedlibrary libheaptrack_inject" \ - --eval-command="call heaptrack_stop()" \ + --eval-command="call (void) heaptrack_stop()" \ --eval-command="detach" # NOTE: we do not call dlclose here, as that has the tendency to trigger # crashes in the debuggee. So instead, we keep heaptrack loaded. @@ -251,7 +325,18 @@ cleanup() { echo "Heaptrack finished! Now run the following to investigate the data:" echo - echo " heaptrack --analyze \"$output\"" + + if [ ! -z "$write_raw_data" ]; then + echo " $UNCOMPRESSOR < \"$output\" | $INTERPRETER | $COMPRESSOR > \"$output_non_raw\"" + else + echo " heaptrack --analyze \"$output\"" + fi + + if [ -z "$record_only" ] && [ -z "$write_raw_data" ] && [ -x "$EXE_PATH/heaptrack_gui" ]; then + echo "" + echo "heaptrack_gui detected, automatically opening the file..." + "$EXE_PATH/heaptrack_gui" "$output" + fi } trap cleanup EXIT @@ -259,7 +344,8 @@ echo "heaptrack output will be written to \"$output\"" if [ -z "$debug" ] && [ -z "$pid" ]; then echo "starting application, this might take some time..." - LD_PRELOAD="$LIBHEAPTRACK_PRELOAD${LD_PRELOAD:+:$LD_PRELOAD}" DUMP_HEAPTRACK_OUTPUT="$pipe" "$client" "$@" + LD_PRELOAD="$asan_ld_preload$LIBHEAPTRACK_PRELOAD${LD_PRELOAD:+:$LD_PRELOAD}" DUMP_HEAPTRACK_OUTPUT="$pipe" "$client" "$@" + EXIT_CODE=$? else if [ -z "$pid" ]; then echo "starting application in GDB, this might take some time..." @@ -267,34 +353,33 @@ else --eval-command="set environment DUMP_HEAPTRACK_OUTPUT=$pipe" \ --eval-command="set startup-with-shell off" \ --eval-command="run" --args "$client" "$@" + EXIT_CODE=$? else echo "injecting heaptrack into application via GDB, this might take some time..." - case $(uname) in - Linux*) - dlopen=__libc_dlopen_mode - ;; - FreeBSD*) - dlopen=dlopen@plt - ;; - esac + dlopen=$($ENVCHECKER dlopen "$LIBHEAPTRACK_INJECT") if [ -z "$debug" ]; then - gdb --batch-silent -n -iex="set auto-solib-add off" -p $pid \ + unset DEBUGINFOD_URLS + gdb --batch-silent -n -iex="set auto-solib-add off" \ + -iex="set language c" -p $pid \ --eval-command="sharedlibrary libc.so" \ - --eval-command="call (void) '$dlopen'(\"$LIBHEAPTRACK_INJECT\", 0x80000000 | 0x002)" \ + --eval-command="call (void) $dlopen" \ --eval-command="sharedlibrary libheaptrack_inject" \ --eval-command="call (void) heaptrack_inject(\"$pipe\")" \ --eval-command="detach" else - gdb --quiet -p $pid \ + echo $dlopen + gdb --quiet -iex="set language c" -p $pid \ --eval-command="sharedlibrary libc.so" \ - --eval-command="call (void) '$dlopen'(\"$LIBHEAPTRACK_INJECT\", 0x80000000 | 0x002)" \ + --eval-command="print (void*) $dlopen" \ --eval-command="sharedlibrary libheaptrack_inject" \ --eval-command="call (void) heaptrack_inject(\"$pipe\")" fi + EXIT_CODE=$? echo "injection finished" fi fi wait $debuggee +exit $EXIT_CODE # kate: hl Bash diff --git a/src/track/heaptrack_api.h b/src/track/heaptrack_api.h index b8dcfc6a..f634ae5b 100644 --- a/src/track/heaptrack_api.h +++ b/src/track/heaptrack_api.h @@ -1,20 +1,8 @@ /* - * Copyright 2016-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2016-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ /** * @file heaptrack_api.h diff --git a/src/track/heaptrack_env.cpp b/src/track/heaptrack_env.cpp new file mode 100644 index 00000000..36da2ff5 --- /dev/null +++ b/src/track/heaptrack_env.cpp @@ -0,0 +1,61 @@ +/* + SPDX-FileCopyrightText: 2022 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include +#include +#include + +#include + +extern "C" { +__attribute__((weak)) void* __libc_dlopen_mode(const char* filename, int flag); +} + +namespace { +void dlopenLine(const char* lib) +{ +#ifdef __FreeBSD__ + + fprintf(stdout, "'dlopen@plt'(\"%s\", 0x%x)\n", lib, RTLD_NOW); + +#else + + if (&__libc_dlopen_mode) { + // __libc_dlopen_mode was available directly in glibc before libdl got merged into it + fprintf(stdout, "__libc_dlopen_mode(\"%s\", 0x80000000 | 0x002)\n", lib); + return; + } + +#ifdef __USE_GNU + fprintf(stdout, "dlmopen(0x%x, \"%s\", 0x%x)\n", LM_ID_BASE, lib, RTLD_NOW); +#else + fprintf(stdout, "dlopen(\"%s\", 0x%x)\n", lib, RTLD_NOW); +#endif + +#endif +} +} + +int main(int argc, char** argv) +{ + if (argc < 2) { + fprintf(stderr, "missing check\n"); + return EXIT_FAILURE; + } + + const auto check = argv[1]; + if (strcmp(check, "dlopen") == 0) { + if (argc != 3) { + fprintf(stderr, "missing lib arg\n"); + return EXIT_FAILURE; + } + dlopenLine(argv[2]); + return EXIT_SUCCESS; + } + + fprintf(stderr, "unsupported check %s\n", check); + return EXIT_FAILURE; +} diff --git a/src/track/heaptrack_inject.cpp b/src/track/heaptrack_inject.cpp index d25feacf..bca24379 100644 --- a/src/track/heaptrack_inject.cpp +++ b/src/track/heaptrack_inject.cpp @@ -1,34 +1,27 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "libheaptrack.h" #include "util/config.h" #include "util/linewriter.h" +#include + #include #include #include #include +#include #include #include +#include #include +#include #include @@ -38,10 +31,16 @@ * @brief Experimental support for symbol overloading after runtime injection. */ +#if ULONG_MAX == 0xffffffffffffffff +#define WORDSIZE 64 +#elif ULONG_MAX == 0xffffffff +#define WORDSIZE 32 +#endif + #ifndef ELF_R_SYM -#if __WORDSIZE == 64 +#if WORDSIZE == 64 #define ELF_R_SYM(i) ELF64_R_SYM(i) -#elif __WORDSIZE == 32 +#elif WORDSIZE == 32 #define ELF_R_SYM(i) ELF32_R_SYM(i) #else #error unsupported word size @@ -49,25 +48,55 @@ #endif #ifndef ElfW -#if __WORDSIZE == 64 +#if WORDSIZE == 64 #define ElfW(type) Elf64_##type -#elif __WORDSIZE == 32 +#elif WORDSIZE == 32 #define ElfW(type) Elf32_##type #else #error unsupported word size #endif #endif +// NOTE: adding noexcept to C functions is a hard error in clang++ +// (but not even a warning in GCC, even with -Wall) +#if defined(__GNUC__) && !defined(__clang__) +#define LIBC_FUN_ATTRS noexcept +#else +#define LIBC_FUN_ATTRS +#endif + +extern "C" { + +// Foward declare mimalloc (https://github.com/microsoft/mimalloc) functions so we don't need to include its .h. +__attribute__((weak)) void* mi_malloc(size_t size) LIBC_FUN_ATTRS; +__attribute__((weak)) void* mi_calloc(size_t count, size_t size) LIBC_FUN_ATTRS; +__attribute__((weak)) void* mi_realloc(void* p, size_t newsize) LIBC_FUN_ATTRS; +__attribute__((weak)) void mi_free(void* p) LIBC_FUN_ATTRS; +} + namespace { namespace Elf { +using Ehdr = ElfW(Ehdr); +using Shdr = ElfW(Shdr); +using Half = ElfW(Half); using Addr = ElfW(Addr); using Dyn = ElfW(Dyn); using Rel = ElfW(Rel); using Rela = ElfW(Rela); using Sym = ElfW(Sym); +#if WORDSIZE == 64 using Sxword = ElfW(Sxword); using Xword = ElfW(Xword); +#else +// FreeBSD elf32.h doesn't define Elf32_Sxword or _Xword. This is used in struct +// elftable, where it's used as a tag value. Our Elf32_Dyn uses Elf32_Sword there, +// as does the Linux definition (and the standard); the El64_Dyn uses Sxword. +// +// Linux elf.h defines Elf32_Sxword as a 64-bit quantity, so let's do that +using Sxword = int64_t; +using Xword = uint64_t; +#endif } void overwrite_symbols() noexcept; @@ -106,8 +135,10 @@ struct realloc static void* hook(void* ptr, size_t size) noexcept { + auto inPtr = reinterpret_cast(ptr); auto ret = original(ptr, size); - heaptrack_realloc(ptr, size, ret); + heaptrack_realloc2(inPtr, size, reinterpret_cast(ret)); + return ret; } }; @@ -185,6 +216,58 @@ struct posix_memalign } }; +// mimalloc functions +struct mi_malloc +{ + static constexpr auto name = "mi_malloc"; + static constexpr auto original = &::mi_malloc; + + static void* hook(size_t size) noexcept + { + auto ptr = original(size); + heaptrack_malloc(ptr, size); + return ptr; + } +}; + +struct mi_free +{ + static constexpr auto name = "mi_free"; + static constexpr auto original = &::mi_free; + + static void hook(void* ptr) noexcept + { + heaptrack_free(ptr); + original(ptr); + } +}; + +struct mi_realloc +{ + static constexpr auto name = "mi_realloc"; + static constexpr auto original = &::mi_realloc; + + static void* hook(void* ptr, size_t size) noexcept + { + auto ret = original(ptr, size); + heaptrack_realloc(ptr, size, ret); + return ret; + } +}; + +struct mi_calloc +{ + static constexpr auto name = "mi_calloc"; + static constexpr auto original = &::mi_calloc; + + static void* hook(size_t num, size_t size) noexcept + { + auto ptr = original(num, size); + heaptrack_malloc(ptr, num * size); + return ptr; + } +}; + template bool hook(const char* symname, Elf::Addr addr, bool restore) { @@ -222,7 +305,10 @@ void apply(const char* symname, Elf::Addr addr, bool restore) || hook(symname, addr, restore) #endif || hook(symname, addr, restore) || hook(symname, addr, restore) - || hook(symname, addr, restore); + || hook(symname, addr, restore) + // mimalloc functions + || hook(symname, addr, restore) || hook(symname, addr, restore) + || hook(symname, addr, restore) || hook(symname, addr, restore); } } @@ -230,13 +316,13 @@ template struct elftable { using type = T; - T* table = nullptr; - Elf::Xword size = {}; + Elf::Addr table = 0; + Elf::Xword size = 0; bool consume(const Elf::Dyn* dyn) noexcept { if (dyn->d_tag == AddrTag) { - table = reinterpret_cast(dyn->d_un.d_ptr); + table = dyn->d_un.d_ptr; return true; } else if (dyn->d_tag == SizeTag) { size = dyn->d_un.d_val; @@ -244,19 +330,34 @@ struct elftable } return false; } + + explicit operator bool() const noexcept + { + return table && size; + } + + T* start(Elf::Addr tableOffset) const noexcept + { + return reinterpret_cast(table + tableOffset); + } + + T* end(Elf::Addr tableOffset) const noexcept + { + return reinterpret_cast(table + tableOffset + size); + } }; using elf_string_table = elftable; using elf_rel_table = elftable; using elf_rela_table = elftable; using elf_jmprel_table = elftable; -using elf_symbol_table = elftable; +using elf_symbol_table = elftable; template void try_overwrite_elftable(const Table& jumps, const elf_string_table& strings, const elf_symbol_table& symbols, - const Elf::Addr base, const bool restore) noexcept + const Elf::Addr base, const bool restore, const Elf::Xword symtabSize) noexcept { - const auto elf_base = + Elf::Addr tableOffset = #ifdef __linux__ 0; // Already has memory addresses #elif defined(__FreeBSD__) @@ -264,19 +365,38 @@ void try_overwrite_elftable(const Table& jumps, const elf_string_table& strings, #else #error port me #endif - const auto rela_start = reinterpret_cast(reinterpret_cast(jumps.table) + elf_base); - const auto rela_end = reinterpret_cast(reinterpret_cast(jumps.table) + jumps.size + elf_base); - const auto sym_start = reinterpret_cast(reinterpret_cast(symbols.table) + elf_base); - const auto str_start = reinterpret_cast(strings.table) + elf_base; + + const auto rela_start = jumps.start(tableOffset); + const auto rela_end = jumps.end(tableOffset); + + const auto sym_start = symbols.start(tableOffset); + const auto sym_end = symbols.start(tableOffset + symtabSize); + const auto num_syms = static_cast(sym_end - sym_start); + + const auto str_start = strings.start(tableOffset); + const auto str_end = strings.end(tableOffset); + const auto num_str = static_cast(str_end - str_start); + for (auto rela = rela_start; rela < rela_end; rela++) { - const auto index = ELF_R_SYM(rela->r_info); - const char* symname = str_start + sym_start[index].st_name; + const auto sym_index = ELF_R_SYM(rela->r_info); + if (sym_index < 0 || sym_index >= num_syms) { + continue; + } + + const auto str_index = sym_start[sym_index].st_name; + if (str_index < 0 || str_index >= num_str) { + continue; + } + + const char* symname = str_start + str_index; + auto addr = rela->r_offset + base; hooks::apply(symname, addr, restore); } } -void try_overwrite_symbols(const Elf::Dyn* dyn, const Elf::Addr base, const bool restore) noexcept +void try_overwrite_symbols(const Elf::Dyn* dyn, const Elf::Addr base, const bool restore, + const Elf::Xword symtabSize) noexcept { elf_symbol_table symbols; elf_rel_table rels; @@ -289,10 +409,92 @@ void try_overwrite_symbols(const Elf::Dyn* dyn, const Elf::Addr base, const bool symbols.consume(dyn) || strings.consume(dyn) || rels.consume(dyn) || relas.consume(dyn) || jmprels.consume(dyn); } + if (!symbols || !strings) { + return; + } + // find symbols to overwrite - try_overwrite_elftable(rels, strings, symbols, base, restore); - try_overwrite_elftable(relas, strings, symbols, base, restore); - try_overwrite_elftable(jmprels, strings, symbols, base, restore); + if (rels) { + try_overwrite_elftable(rels, strings, symbols, base, restore, symtabSize); + } + + if (relas) { + try_overwrite_elftable(relas, strings, symbols, base, restore, symtabSize); + } + + if (jmprels) { + try_overwrite_elftable(jmprels, strings, symbols, base, restore, symtabSize); + } +} + +template +struct ScopeGuard +{ + ScopeGuard(Cleanup cleanup) + : cleanup(std::move(cleanup)) + { + } + + ~ScopeGuard() + { + cleanup(); + } + + Cleanup cleanup; +}; + +template +auto scopeGuard(Cleanup cleanup) +{ + return ScopeGuard(std::move(cleanup)); +} + +Elf::Xword symtabSize(const char* path) +{ + auto fd = open(path, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "open failed: %s %s\n", path, strerror(errno)); + return 0; + } + auto closeOnExit = scopeGuard([fd]() { close(fd); }); + + struct stat stat_info; + if (fstat(fd, &stat_info) != 0) { + fprintf(stderr, "stat failed: %s %s\n", path, strerror(errno)); + return 0; + } + + auto mapping = mmap(nullptr, stat_info.st_size, PROT_READ, MAP_SHARED, fd, 0); + auto unmapOnExit = scopeGuard([&]() { munmap(mapping, stat_info.st_size); }); + + const auto base = reinterpret_cast(mapping); + const auto ehdr = reinterpret_cast(base); + const auto shdr = reinterpret_cast(base + ehdr->e_shoff); + + for (ElfW(Half) i = 0; i < ehdr->e_shnum; ++i) { + if (shdr[i].sh_type == SHT_DYNSYM) { + return shdr[i].sh_size; + } + } + + fprintf(stderr, "failed to query symtab size: %s\n", path); + return 0; +} + +Elf::Xword cachedSymtabSize(const char* path) +{ + if (!strlen(path)) { + path = "/proc/self/exe"; + } + + static tsl::robin_map cache; + + auto key = std::string(path); + auto it = cache.find(path); + if (it == cache.end()) { + it = cache.insert(it, {std::move(key), symtabSize(path)}); + } + return it->second; } int iterate_phdrs(dl_phdr_info* info, size_t /*size*/, void* data) noexcept @@ -304,12 +506,16 @@ int iterate_phdrs(dl_phdr_info* info, size_t /*size*/, void* data) noexcept // prevent strange crashes due to overwriting the free symbol in ld-linux // (doesn't seem to be necessary in FreeBSD's ld-elf) return 0; + } else if (strstr(info->dlpi_name, "linux-vdso.so")) { + // don't overwrite anything within linux-vdso + return 0; } + const auto symtabSize = cachedSymtabSize(info->dlpi_name); for (auto phdr = info->dlpi_phdr, end = phdr + info->dlpi_phnum; phdr != end; ++phdr) { if (phdr->p_type == PT_DYNAMIC) { try_overwrite_symbols(reinterpret_cast(phdr->p_vaddr + info->dlpi_addr), info->dlpi_addr, - data != nullptr); + data != nullptr, symtabSize); } } return 0; @@ -319,15 +525,36 @@ void overwrite_symbols() noexcept { dl_iterate_phdr(&iterate_phdrs, nullptr); } + +void restore_symbols() noexcept +{ + bool do_shutdown = true; + dl_iterate_phdr(&iterate_phdrs, &do_shutdown); +} } extern "C" { +// this function is called when heaptrack_inject is runtime injected via GDB void heaptrack_inject(const char* outputFileName) noexcept { - heaptrack_init(outputFileName, []() { overwrite_symbols(); }, [](LineWriter& out) { out.write("A\n"); }, - []() { - bool do_shutdown = true; - dl_iterate_phdr(&iterate_phdrs, &do_shutdown); - }); + heaptrack_init( + outputFileName, &overwrite_symbols, [](LineWriter& out) { out.write("A\n"); }, &restore_symbols); } } + +// alternatively, the code below may initialize heaptrack when we use +// heaptrack_inject via LD_PRELOAD and have the right environment variables setup +struct HeaptrackInjectPreloadInitialization +{ + HeaptrackInjectPreloadInitialization() + { + const auto outputFileName = getenv("DUMP_HEAPTRACK_OUTPUT"); + if (!outputFileName) { + // when the env var wasn't set, then this means we got runtime injected, don't do anything here + return; + } + heaptrack_init(outputFileName, &overwrite_symbols, nullptr, &restore_symbols); + } +}; + +static HeaptrackInjectPreloadInitialization heaptrackInjectPreloadInitialization; diff --git a/src/track/heaptrack_preload.cpp b/src/track/heaptrack_preload.cpp index 93d30fa6..3f7478fa 100644 --- a/src/track/heaptrack_preload.cpp +++ b/src/track/heaptrack_preload.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "libheaptrack.h" #include "util/config.h" @@ -27,6 +15,8 @@ #include #include +#include +#include using namespace std; @@ -36,11 +26,59 @@ using namespace std; #define HAVE_ALIGNED_ALLOC 0 #endif +// NOTE: adding noexcept to C functions is a hard error in clang++ +// (but not even a warning in GCC, even with -Wall) +#if defined(__GNUC__) && !defined(__clang__) +#define LIBC_FUN_ATTRS noexcept +#else +#define LIBC_FUN_ATTRS +#endif + +extern "C" { + +// Foward declare mimalloc (https://github.com/microsoft/mimalloc) functions so we don't need to include its .h. +void* mi_malloc(size_t size) LIBC_FUN_ATTRS; +void* mi_calloc(size_t count, size_t size) LIBC_FUN_ATTRS; +void* mi_realloc(void* p, size_t newsize) LIBC_FUN_ATTRS; +void mi_free(void* p) LIBC_FUN_ATTRS; +} + +extern "C" { +struct BlkInfo_ +{ + void* base; + size_t size; + uint attr; +}; + +enum +{ + BLK_ATTR_FINALIZE = 0x01 +}; + +void *gc_malloc(size_t sz, uint32_t ba = 0, const void *ti = nullptr); +void *gc_calloc(size_t sz, uint32_t ba = 0, const void *ti = nullptr); +BlkInfo_ gc_qalloc(size_t sz, uint32_t ba = 0, const void *ti = nullptr); +void *gc_realloc(void* p, size_t sz, uint32_t ba = 0, const void *ti = nullptr); +size_t gc_extend(void* p, size_t mx, size_t sz, const void *ti = nullptr); +uint32_t gc_setAttr(void* p, uint32_t a); +uint32_t gc_getAttr(void* p); +uint32_t gc_clrAttr(void* p, uint32_t a); +BlkInfo_ gc_query(void* p); +void rt_finalizeFromGC(void* p, size_t size, uint32_t attr); +} + namespace { namespace hooks { -template +enum class HookType +{ + Required, + Optional +}; + +template struct hook { Signature original = nullptr; @@ -48,6 +86,9 @@ struct hook void init() noexcept { auto ret = dlsym(RTLD_NEXT, Base::identifier); + if (!ret && Type == HookType::Optional) { + return; + } if (!ret) { fprintf(stderr, "Could not find original function %s\n", Base::identifier); abort(); @@ -67,8 +108,8 @@ struct hook } }; -#define HOOK(name) \ - struct name##_t : public hook \ +#define HOOK(name, type) \ + struct name##_t : public hook \ { \ static constexpr const char* identifier = #name; \ } name @@ -76,22 +117,40 @@ struct hook #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wignored-attributes" -HOOK(malloc); -HOOK(free); -HOOK(calloc); +HOOK(malloc, HookType::Required); +HOOK(free, HookType::Required); +HOOK(calloc, HookType::Required); #if HAVE_CFREE -HOOK(cfree); +HOOK(cfree, HookType::Optional); #endif -HOOK(realloc); -HOOK(posix_memalign); +HOOK(realloc, HookType::Required); +HOOK(posix_memalign, HookType::Optional); #if HAVE_VALLOC -HOOK(valloc); +HOOK(valloc, HookType::Optional); #endif #if HAVE_ALIGNED_ALLOC -HOOK(aligned_alloc); +HOOK(aligned_alloc, HookType::Optional); #endif -HOOK(dlopen); -HOOK(dlclose); +HOOK(dlopen, HookType::Required); +HOOK(dlclose, HookType::Required); + +// mimalloc functions +HOOK(mi_malloc, HookType::Optional); +HOOK(mi_calloc, HookType::Optional); +HOOK(mi_realloc, HookType::Optional); +HOOK(mi_free, HookType::Optional); + +// D GC functions +HOOK(gc_malloc, HookType::Required); +HOOK(gc_calloc, HookType::Required); +HOOK(gc_qalloc, HookType::Required); +HOOK(gc_realloc, HookType::Required); +HOOK(gc_extend, HookType::Required); +HOOK(rt_finalizeFromGC, HookType::Required); +HOOK(gc_setAttr, HookType::Required); +HOOK(gc_clrAttr, HookType::Required); +HOOK(gc_getAttr, HookType::Required); +HOOK(gc_query, HookType::Required); #pragma GCC diagnostic pop #undef HOOK @@ -145,30 +204,49 @@ void init() // heaptrack_init itself calls calloc via std::mutex/_libpthread_init on FreeBSD hooks::calloc.original = &dummy_calloc; hooks::calloc.init(); - heaptrack_init(getenv("DUMP_HEAPTRACK_OUTPUT"), - [] { - hooks::dlopen.init(); - hooks::dlclose.init(); - hooks::malloc.init(); - hooks::free.init(); - hooks::calloc.init(); + heaptrack_init( + getenv("DUMP_HEAPTRACK_OUTPUT"), + [] { + hooks::dlopen.init(); + hooks::dlclose.init(); + hooks::malloc.init(); + hooks::free.init(); + hooks::calloc.init(); #if HAVE_CFREE - hooks::cfree.init(); + hooks::cfree.init(); #endif - hooks::realloc.init(); - hooks::posix_memalign.init(); + hooks::realloc.init(); + hooks::posix_memalign.init(); #if HAVE_VALLOC - hooks::valloc.init(); + hooks::valloc.init(); #endif #if HAVE_ALIGNED_ALLOC - hooks::aligned_alloc.init(); + hooks::aligned_alloc.init(); #endif - // cleanup environment to prevent tracing of child apps - unsetenv("LD_PRELOAD"); - unsetenv("DUMP_HEAPTRACK_OUTPUT"); - }, - nullptr, nullptr); + // mimalloc functions + hooks::mi_malloc.init(); + hooks::mi_calloc.init(); + hooks::mi_realloc.init(); + hooks::mi_free.init(); + + // D GC functions + hooks::gc_malloc.init(); + hooks::gc_calloc.init(); + hooks::gc_qalloc.init(); + hooks::gc_realloc.init(); + hooks::gc_extend.init(); + hooks::rt_finalizeFromGC.init(); + hooks::gc_setAttr.init(); + hooks::gc_clrAttr.init(); + hooks::gc_getAttr.init(); + hooks::gc_query.init(); + + // cleanup environment to prevent tracing of child apps + unsetenv("LD_PRELOAD"); + unsetenv("DUMP_HEAPTRACK_OUTPUT"); + }, + nullptr, nullptr); } } } @@ -177,14 +255,6 @@ extern "C" { /// TODO: memalign, pvalloc, ...? -// NOTE: adding noexcept to C functions is a hard error in clang++ -// (but not even a warning in GCC, even with -Wall) -#if defined(__GNUC__) && !defined(__clang__) -#define LIBC_FUN_ATTRS noexcept -#else -#define LIBC_FUN_ATTRS -#endif - void* malloc(size_t size) LIBC_FUN_ATTRS { if (!hooks::malloc) { @@ -317,6 +387,18 @@ void* dlopen(const char* filename, int flag) LIBC_FUN_ATTRS hooks::init(); } +#ifdef RTLD_DEEPBIND + if (filename && flag & RTLD_DEEPBIND) { + heaptrack_warning([](FILE* out) { + fprintf(out, + "Detected dlopen call with RTLD_DEEPBIND which breaks function call interception. " + "Heaptrack will drop this flag. If your application relies on it, try to run `heaptrack " + "--use-inject` instead."); + }); + flag &= ~RTLD_DEEPBIND; + } +#endif + void* ret = hooks::dlopen(filename, flag); if (ret) { @@ -340,4 +422,289 @@ int dlclose(void* handle) LIBC_FUN_ATTRS return ret; } + +// mimalloc functions, implementations just copied from above and names changed +void* mi_malloc(size_t size) LIBC_FUN_ATTRS +{ + if (!hooks::mi_malloc) { + hooks::init(); + } + + void* ptr = hooks::mi_malloc(size); + heaptrack_malloc(ptr, size); + return ptr; +} + +void* mi_realloc(void* ptr, size_t size) LIBC_FUN_ATTRS +{ + if (!hooks::mi_realloc) { + hooks::init(); + } + + void* ret = hooks::mi_realloc(ptr, size); + + if (ret) { + heaptrack_realloc(ptr, size, ret); + } + + return ret; +} + +void* mi_calloc(size_t num, size_t size) LIBC_FUN_ATTRS +{ + if (!hooks::mi_calloc) { + hooks::init(); + } + + void* ret = hooks::mi_calloc(num, size); + + if (ret) { + heaptrack_malloc(ret, num * size); + } + + return ret; +} + +void mi_free(void* ptr) LIBC_FUN_ATTRS +{ + if (!hooks::mi_free) { + hooks::init(); + } + + if (hooks::dummyPool().isDummyAllocation(ptr)) { + return; + } + + // call handler before handing over the real free implementation + // to ensure the ptr is not reused in-between and thus the output + // stays consistent + heaptrack_free(ptr); + + hooks::mi_free(ptr); +} + +/* + * The finalizer bit is set for every allocation on the D GC heap. + * This makes sure rt_finalizeFromGC is called for every freed pointer. + * Because the real rt_finalizeFromGC will crash for a pointer without + * a finalizer, we have to remember the pointers with a real finalizer + * in pointers_with_finalizer. + */ +static std::unordered_set pointers_with_finalizer; +static std::mutex pointers_with_finalizer_mutex; + +/* + * The first allocations on the D GC heap uses ProtoGC, which + * initializes the real GC and forwards the call. This will look like + * two allocation and has to be handled specially. + */ +static thread_local int gc_recursive = 0; + +void *gc_malloc(size_t size, uint32_t ba, const void *ti) +{ + if (!hooks::gc_malloc) { + hooks::init(); + } + + gc_recursive++; + void* ptr = hooks::gc_malloc(size, ba, ti); + gc_recursive--; + if (gc_recursive) { + return ptr; + } + + uint32_t attr = hooks::gc_getAttr(ptr); + if(attr & BLK_ATTR_FINALIZE) { + pointers_with_finalizer_mutex.lock(); + pointers_with_finalizer.insert(ptr); + pointers_with_finalizer_mutex.unlock(); + } + hooks::gc_setAttr(ptr, BLK_ATTR_FINALIZE); + heaptrack_malloc(ptr, size); + return ptr; +} + +void *gc_calloc(size_t size, uint32_t ba, const void *ti) +{ + if (!hooks::gc_calloc) { + hooks::init(); + } + + gc_recursive++; + void* ptr = hooks::gc_calloc(size, ba, ti); + gc_recursive--; + if (gc_recursive) { + return ptr; + } + + uint32_t attr = hooks::gc_getAttr(ptr); + if (attr & BLK_ATTR_FINALIZE) { + pointers_with_finalizer_mutex.lock(); + pointers_with_finalizer.insert(ptr); + pointers_with_finalizer_mutex.unlock(); + } + hooks::gc_setAttr(ptr, BLK_ATTR_FINALIZE); + heaptrack_malloc(ptr, size); + return ptr; +} + +BlkInfo_ gc_qalloc(size_t size, uint32_t ba, const void *ti) +{ + if (!hooks::gc_qalloc) { + hooks::init(); + } + + gc_recursive++; + BlkInfo_ block = hooks::gc_qalloc(size, ba, ti); + gc_recursive--; + if(gc_recursive) { + return block; + } + + uint32_t attr = hooks::gc_getAttr(block.base); + if (attr & BLK_ATTR_FINALIZE) { + pointers_with_finalizer_mutex.lock(); + pointers_with_finalizer.insert(block.base); + pointers_with_finalizer_mutex.unlock(); + } + hooks::gc_setAttr(block.base, BLK_ATTR_FINALIZE); + heaptrack_malloc(block.base, block.size); + return block; +} + +void *gc_realloc(void* p, size_t size, uint32_t ba, const void *ti) +{ + if (!hooks::gc_realloc) { + hooks::init(); + } + + gc_recursive++; + void* ret = hooks::gc_realloc(p, size, ba, ti); + gc_recursive--; + if (gc_recursive) { + return ret; + } + + if (ret) { + if (ret != p) { + pointers_with_finalizer_mutex.lock(); + std::unordered_set::iterator it = pointers_with_finalizer.find(p); + if (it != pointers_with_finalizer.end()) { + pointers_with_finalizer.erase(it); + pointers_with_finalizer.insert(ret); + } + pointers_with_finalizer_mutex.unlock(); + } + heaptrack_realloc(p, size, ret); + } + return ret; +} + +size_t gc_extend(void* p, size_t mx, size_t sz, const void *ti) +{ + if (!hooks::gc_extend) { + hooks::init(); + } + + size_t ret = hooks::gc_extend(p, mx, sz, ti); + if (ret) { + heaptrack_realloc(p, ret, p); + } + return ret; +} + +uint32_t gc_setAttr(void* p, uint32_t a) +{ + if (!hooks::gc_setAttr) { + hooks::init(); + } + + pointers_with_finalizer_mutex.lock(); + bool hasFinalizer = pointers_with_finalizer.find(p) != pointers_with_finalizer.end(); + if (a & BLK_ATTR_FINALIZE) { + pointers_with_finalizer.insert(p); + } + pointers_with_finalizer_mutex.unlock(); + + uint32_t r = hooks::gc_setAttr(p, a); + if (!hasFinalizer) { + r &= ~BLK_ATTR_FINALIZE; + } + return r; +} + +uint32_t gc_clrAttr(void* p, uint32_t a) +{ + if (!hooks::gc_clrAttr) { + hooks::init(); + } + + pointers_with_finalizer_mutex.lock(); + bool hasFinalizer = pointers_with_finalizer.find(p) != pointers_with_finalizer.end(); + if (a & BLK_ATTR_FINALIZE) { + pointers_with_finalizer.erase(pointers_with_finalizer.find(p)); + } + pointers_with_finalizer_mutex.unlock(); + + uint32_t r = hooks::gc_clrAttr(p, a & ~BLK_ATTR_FINALIZE); + if (!hasFinalizer) { + r &= ~BLK_ATTR_FINALIZE; + } + return r; +} + +uint32_t gc_getAttr(void* p) +{ + if (!hooks::gc_getAttr) { + hooks::init(); + } + + pointers_with_finalizer_mutex.lock(); + bool hasFinalizer = pointers_with_finalizer.find(p) != pointers_with_finalizer.end(); + pointers_with_finalizer_mutex.unlock(); + + uint32_t r = hooks::gc_getAttr(p); + if (!hasFinalizer) { + r &= ~BLK_ATTR_FINALIZE; + } + return r; +} + +BlkInfo_ gc_query(void* p) +{ + if (!hooks::gc_query) { + hooks::init(); + } + + pointers_with_finalizer_mutex.lock(); + bool hasFinalizer = pointers_with_finalizer.find(p) != pointers_with_finalizer.end(); + pointers_with_finalizer_mutex.unlock(); + + BlkInfo_ ret = hooks::gc_query(p); + if (!hasFinalizer) { + ret.attr &= ~BLK_ATTR_FINALIZE; + } + return ret; +} + +void rt_finalizeFromGC(void* p, size_t size, uint32_t attr) +{ + if (!hooks::rt_finalizeFromGC) { + hooks::init(); + } + heaptrack_free(p); + + pointers_with_finalizer_mutex.lock(); + std::unordered_set::iterator it = pointers_with_finalizer.find(p); + bool hasFinalizer = false; + if (it != pointers_with_finalizer.end()) { + pointers_with_finalizer.erase(it); + hasFinalizer = true; + } + pointers_with_finalizer_mutex.unlock(); + + if (hasFinalizer) { + hooks::rt_finalizeFromGC(p, size, attr); + } +} } diff --git a/src/track/libheaptrack.cpp b/src/track/libheaptrack.cpp index 8a845b0d..9ce816d9 100644 --- a/src/track/libheaptrack.cpp +++ b/src/track/libheaptrack.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ /** * @file libheaptrack.cpp @@ -35,11 +23,11 @@ #include #endif #ifdef __FreeBSD__ +#include #include -#include #include +#include #include -#include #endif #include @@ -47,19 +35,20 @@ #include #include #include +#include #include #include -#include - -#include #include "tracetree.h" #include "util/config.h" #include "util/libunwind_config.h" #include "util/linewriter.h" +#include "util/macroutils.h" extern "C" { -__attribute__((weak)) void __libc_freeres(); +// see upstream "documentation" at: +// https://github.com/llvm-mirror/compiler-rt/blob/master/include/sanitizer/lsan_interface.h#L76 +__attribute__((weak)) const char* __lsan_default_suppressions(); } namespace __gnu_cxx { __attribute__((weak)) extern void __freeres(); @@ -72,6 +61,10 @@ __attribute__((weak)) extern void __freeres(); */ // #define DEBUG_MALLOC_PTRS +#ifdef DEBUG_MALLOC_PTRS +#include +#endif + using namespace std; namespace { @@ -88,7 +81,7 @@ chrono::milliseconds elapsedTime() return chrono::duration_cast(clock::now() - startTime()); } -__pid_t gettid() +pid_t gettid() { #ifdef __linux__ return syscall(SYS_gettid); @@ -122,6 +115,7 @@ thread_local bool RecursionGuard::isActive = false; enum DebugVerbosity { + WarningOutput, NoDebugOutput, MinimalOutput, VerboseOutput, @@ -135,20 +129,34 @@ constexpr const DebugVerbosity s_debugVerbosity = NoDebugOutput; * Call this to optionally show debug information but give the compiler * a hand in removing it all if debug output is disabled. */ -template -inline void debugLog(const char fmt[], Args... args) +template +inline void debugLog(Callback callback) { if (debugLevel <= s_debugVerbosity) { RecursionGuard guard; flockfile(stderr); - fprintf(stderr, "heaptrack debug(%d) [%d:%d]@%" PRIu64 " ", static_cast(debugLevel), getpid(), gettid(), - elapsedTime().count()); - fprintf(stderr, fmt, args...); + if (debugLevel == WarningOutput) { + fprintf(stderr, "heaptrack warning [%d:%d]@%" PRIu64 " ", getpid(), gettid(), elapsedTime().count()); + } else { + fprintf(stderr, "heaptrack debug(%d) [%d:%d]@%" PRIu64 " ", debugLevel, getpid(), gettid(), + elapsedTime().count()); + } + callback(stderr); fputc('\n', stderr); funlockfile(stderr); } } +/** + * Call this to optionally show debug information but give the compiler + * a hand in removing it all if debug output is disabled. + */ +template +inline void debugLog(const char fmt[], Args... args) +{ + debugLog([&](FILE* out) { fprintf(out, fmt, args...); }); +} + void printBacktrace() { if (s_debugVerbosity == NoDebugOutput) @@ -163,13 +171,34 @@ void printBacktrace() * Set to true in an atexit handler. In such conditions, the stop callback * will not be called. */ -atomic s_atexit{false}; +atomic s_atexit {false}; /** * Set to true in heaptrack_stop, when s_atexit was not yet set. In such conditions, * we always fully unload and cleanup behind ourselves */ -atomic s_forceCleanup{false}; +atomic s_forceCleanup {false}; + +// based on: https://stackoverflow.com/a/24315631/35250 +void replaceAll(string& str, const string& search, const string& replace) +{ + size_t start_pos = 0; + while ((start_pos = str.find(search, start_pos)) != string::npos) { + str.replace(start_pos, search.length(), replace); + start_pos += replace.length(); + } +} + +// see https://bugs.kde.org/show_bug.cgi?id=408547 +// apparently sometimes flock can return EAGAIN, despite that not being a documented return value +static int lockFile(int fd) +{ + int ret = -1; + while ((ret = flock(fd, LOCK_EX | LOCK_NB)) == EAGAIN) { + // try again + } + return ret; +} int createFile(const char* fileName) { @@ -191,7 +220,7 @@ int createFile(const char* fileName) outputFileName = "heaptrack.$$"; } - boost::replace_all(outputFileName, "$$", to_string(getpid())); + replaceAll(outputFileName, "$$", to_string(getpid())); auto out = open(outputFileName.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0644); debugLog("will write to %s/%p\n", outputFileName.c_str(), out); @@ -199,13 +228,13 @@ int createFile(const char* fileName) if (out == -1) { fprintf(stderr, "ERROR: failed to open heaptrack output file %s: %s (%d)\n", outputFileName.c_str(), strerror(errno), errno); - } else if (flock(out, LOCK_EX | LOCK_NB) != 0) { + } else if (lockFile(out) != 0) { #ifdef __FreeBSD__ // pipes do not support flock, create a regular file auto lockpath = outputFileName + ".lock"; auto lockfile = open(lockpath.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0644); debugLog("will lock %s/%p\n", lockpath.c_str(), lockfile); - if (flock(lockfile, LOCK_EX | LOCK_NB) == 0) { + if (lockFile(lockfile) == 0) { // leaking the fd seems fine return out; } @@ -223,22 +252,33 @@ int createFile(const char* fileName) * Thread-Safe heaptrack API * * The only critical section in libheaptrack is the output of the data, - * dl_iterate_phdr - * calls, as well as initialization and shutdown. + * dl_iterate_phdr calls, as well as initialization and shutdown. */ class HeapTrack { public: - HeapTrack(const RecursionGuard& /*recursionGuard*/) + template + static bool op(const RecursionGuard& /*recursionGuard*/, const Op& op) { debugLog("%s", "acquiring lock"); - s_lock.lock(); + + auto locked = tryLock([]() { return s_forceCleanup.load(); }); + if (!locked) { + return false; + } + debugLog("%s", "lock acquired"); + + HeapTrack heaptrack(locked); + op(heaptrack); + + return true; } ~HeapTrack() { debugLog("%s", "releasing lock"); + s_lock.unlock(); } @@ -279,11 +319,6 @@ class HeapTrack if (&__gnu_cxx::__freeres) { __gnu_cxx::__freeres(); } - // free internal libc resources, cf: https://bugs.kde.org/show_bug.cgi?id=378765 - // see also Valgrind's `--run-libc-freeres` option - if (&__libc_freeres) { - __libc_freeres(); - } s_atexit.store(true); heaptrack_stop(); @@ -305,6 +340,7 @@ class HeapTrack writeExe(); writeCommandLine(); writeSystemInfo(); + writeSuppressions(); if (initAfterCallback) { debugLog("%s", "calling initAfterCallback"); @@ -422,14 +458,14 @@ class HeapTrack #ifdef __linux__ ssize_t size = readlink("/proc/self/exe", buf, BUF_SIZE); #elif defined(__FreeBSD__) - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; size_t size = BUF_SIZE; sysctl(mib, 4, buf, &size, NULL, 0); #endif if (size > 0 && size < BUF_SIZE) { buf[size] = 0; - s_data->out.write("x %s\n", buf); + s_data->out.write("x %x %s\n", size, buf); } } @@ -444,7 +480,7 @@ class HeapTrack int bytesRead = read(fd, buf, BUF_SIZE); close(fd); #elif defined(__FreeBSD__) - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() }; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid()}; size_t bytesRead = BUF_SIZE; sysctl(mib, 4, buf, &bytesRead, NULL, 0); #endif @@ -465,6 +501,24 @@ class HeapTrack static_cast(sysconf(_SC_PHYS_PAGES))); } + void writeSuppressions() + { + if (!__lsan_default_suppressions) + return; + + const char* suppressions = __lsan_default_suppressions(); + if (!suppressions) + return; + + std::istringstream stream(suppressions); + std::string line; + while (std::getline(stream, line)) { + s_data->out.write("S "); + s_data->out.write(line); + s_data->out.write("\n"); + } + } + void handleMalloc(void* ptr, size_t size, const Trace& trace) { if (!s_data || !s_data->out.canWrite()) { @@ -472,8 +526,15 @@ class HeapTrack } updateModuleCache(); - const auto index = s_data->traceTree.index( - trace, [](uintptr_t ip, uint32_t index) { return s_data->out.writeHexLine('t', ip, index); }); + const auto index = s_data->traceTree.index(trace, [](uintptr_t ip, uint32_t index) { + // decrement addresses by one - otherwise we misattribute the cost to the wrong instruction + // for some reason, it seems like we always get the instruction _after_ the one we are interested in + // see also: https://github.com/libunwind/libunwind/issues/287 + // and https://bugs.kde.org/show_bug.cgi?id=439897 + --ip; + + return s_data->out.writeHexLine('t', ip, index); + }); #ifdef DEBUG_MALLOC_PTRS auto it = s_data->known.find(ptr); @@ -520,7 +581,7 @@ class HeapTrack debugLog("dlopen_notify_callback: %s %zx", fileName, info->dlpi_addr); - if (!heaptrack->s_data->out.write("m %s %zx", fileName, info->dlpi_addr)) { + if (!heaptrack->s_data->out.write("m %x %s %zx", strlen(fileName), fileName, info->dlpi_addr)) { return 1; } @@ -569,7 +630,7 @@ class HeapTrack return; } debugLog("%s", "updateModuleCache()"); - if (!s_data->out.write("m -\n")) { + if (!s_data->out.write("m 1 -\n")) { return; } dl_iterate_phdr(&dl_iterate_phdr_callback, this); @@ -583,22 +644,47 @@ class HeapTrack shutdown(); } - struct LockCheckFailed{}; + class LockStatus + { + public: + LockStatus(bool isLocked) + : isLocked(isLocked) + { + } + explicit operator bool() const + { + return isLocked; + } + + private: + bool isLocked = false; + }; /** * To prevent deadlocks on shutdown, we try to lock from the timer thread - * and throw an LockCheckFailed exception otherwise. + * + * TODO: c++17 return std::optional */ - template - HeapTrack(AdditionalLockCheck lockCheck) + template + static LockStatus tryLock(StopLockCheck stopLockCheck) { debugLog("%s", "trying to acquire lock"); while (!s_lock.try_lock()) { - if (!lockCheck()) - throw LockCheckFailed(); + if (stopLockCheck()) { + return false; + } this_thread::sleep_for(chrono::microseconds(1)); } debugLog("%s", "lock acquired"); + return true; + } + + /** + * Create locked HeapTrack instance after a successful call to tryLock + */ + HeapTrack(POTENTIALLY_UNUSED LockStatus lockStatus) + { + assert(lockStatus); } struct LockedData @@ -639,13 +725,14 @@ class HeapTrack // TODO: make interval customizable this_thread::sleep_for(chrono::milliseconds(10)); - try { - HeapTrack heaptrack([&] { return !stopTimerThread.load(); }); - heaptrack.writeTimestamp(); - heaptrack.writeRSS(); - } catch (LockCheckFailed) { + const auto locked = tryLock([&] { return stopTimerThread.load(); }); + if (!locked) { break; } + + HeapTrack heaptrack(locked); + heaptrack.writeTimestamp(); + heaptrack.writeRSS(); } }); @@ -694,13 +781,13 @@ class HeapTrack TraceTree traceTree; - atomic stopTimerThread{false}; + atomic stopTimerThread {false}; std::thread timerThread; heaptrack_callback_t stopCallback = nullptr; #ifdef DEBUG_MALLOC_PTRS - unordered_set known; + tsl::robin_set known; #endif }; @@ -712,8 +799,27 @@ class HeapTrack }; std::mutex HeapTrack::s_lock; -HeapTrack::LockedData* HeapTrack::s_data{nullptr}; -std::atomic HeapTrack::s_paused{false}; +HeapTrack::LockedData* HeapTrack::s_data {nullptr}; +std::atomic HeapTrack::s_paused {false}; +} + +static void heaptrack_realloc_impl(void* ptr_in, size_t size, void* ptr_out) +{ + if (!HeapTrack::isPaused() && ptr_out && !RecursionGuard::isActive) { + RecursionGuard guard; + + debugLog("heaptrack_realloc(%p, %zu, %p)", ptr_in, size, ptr_out); + + Trace trace; + trace.fill(2 + HEAPTRACK_DEBUG_BUILD * 3); + + HeapTrack::op(guard, [&](HeapTrack& heaptrack) { + if (ptr_in) { + heaptrack.handleFree(ptr_in); + } + heaptrack.handleMalloc(ptr_out, size, trace); + }); + } } extern "C" { @@ -724,11 +830,14 @@ void heaptrack_init(const char* outputFileName, heaptrack_callback_t initBeforeC RecursionGuard guard; // initialize startTime(); + s_forceCleanup.store(false); debugLog("heaptrack_init(%s)", outputFileName); - HeapTrack heaptrack(guard); - heaptrack.initialize(outputFileName, initBeforeCallback, initAfterCallback, stopCallback); + POTENTIALLY_UNUSED auto ret = HeapTrack::op(guard, [&](HeapTrack& heaptrack) { + heaptrack.initialize(outputFileName, initBeforeCallback, initAfterCallback, stopCallback); + }); + assert(ret); } void heaptrack_stop() @@ -737,13 +846,15 @@ void heaptrack_stop() debugLog("%s", "heaptrack_stop()"); - HeapTrack heaptrack(guard); - - if (!s_atexit) { - s_forceCleanup.store(true); - } + assert(!s_forceCleanup); + POTENTIALLY_UNUSED auto ret = HeapTrack::op(guard, [&](HeapTrack& heaptrack) { + if (!s_atexit) { + s_forceCleanup.store(true); + } - heaptrack.shutdown(); + heaptrack.shutdown(); + }); + assert(ret); } void heaptrack_pause() @@ -764,10 +875,9 @@ void heaptrack_malloc(void* ptr, size_t size) debugLog("heaptrack_malloc(%p, %zu)", ptr, size); Trace trace; - trace.fill(2 + HEAPTRACK_DEBUG_BUILD); + trace.fill(2 + HEAPTRACK_DEBUG_BUILD * 2); - HeapTrack heaptrack(guard); - heaptrack.handleMalloc(ptr, size, trace); + HeapTrack::op(guard, [&](HeapTrack& heaptrack) { heaptrack.handleMalloc(ptr, size, trace); }); } } @@ -778,27 +888,18 @@ void heaptrack_free(void* ptr) debugLog("heaptrack_free(%p)", ptr); - HeapTrack heaptrack(guard); - heaptrack.handleFree(ptr); + HeapTrack::op(guard, [&](HeapTrack& heaptrack) { heaptrack.handleFree(ptr); }); } } void heaptrack_realloc(void* ptr_in, size_t size, void* ptr_out) { - if (!HeapTrack::isPaused() && ptr_out && !RecursionGuard::isActive) { - RecursionGuard guard; - - debugLog("heaptrack_realloc(%p, %zu, %p)", ptr_in, size, ptr_out); - - Trace trace; - trace.fill(2 + HEAPTRACK_DEBUG_BUILD); + heaptrack_realloc_impl(ptr_in, size, ptr_out); +} - HeapTrack heaptrack(guard); - if (ptr_in) { - heaptrack.handleFree(ptr_in); - } - heaptrack.handleMalloc(ptr_out, size, trace); - } +void heaptrack_realloc2(uintptr_t ptr_in, size_t size, uintptr_t ptr_out) +{ + heaptrack_realloc_impl(reinterpret_cast(ptr_in), size, reinterpret_cast(ptr_out)); } void heaptrack_invalidate_module_cache() @@ -807,7 +908,13 @@ void heaptrack_invalidate_module_cache() debugLog("%s", "heaptrack_invalidate_module_cache()"); - HeapTrack heaptrack(guard); - heaptrack.invalidateModuleCache(); + HeapTrack::op(guard, [&](HeapTrack& heaptrack) { heaptrack.invalidateModuleCache(); }); +} + +void heaptrack_warning(heaptrack_warning_callback_t callback) +{ + RecursionGuard guard; + + debugLog(callback); } } diff --git a/src/track/libheaptrack.h b/src/track/libheaptrack.h index a865838f..66bef407 100644 --- a/src/track/libheaptrack.h +++ b/src/track/libheaptrack.h @@ -1,22 +1,12 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include +#include +#include #ifdef __cplusplus typedef class LineWriter linewriter_t; @@ -42,9 +32,13 @@ void heaptrack_malloc(void* ptr, size_t size); void heaptrack_free(void* ptr); void heaptrack_realloc(void* ptr_in, size_t size, void* ptr_out); +void heaptrack_realloc2(uintptr_t ptr_in, size_t size, uintptr_t ptr_out); void heaptrack_invalidate_module_cache(); +typedef void (*heaptrack_warning_callback_t)(FILE*); +void heaptrack_warning(heaptrack_warning_callback_t callback); + #ifdef __cplusplus } #endif diff --git a/src/track/trace.h b/src/track/trace.h index 1fa1dcb5..538e8b25 100644 --- a/src/track/trace.h +++ b/src/track/trace.h @@ -1,24 +1,15 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TRACE_H #define TRACE_H +#include +#include + /** * @brief Backtrace interface. */ @@ -64,13 +55,25 @@ struct Trace return m_size > 0; } + void fillTestData(uintptr_t n, uintptr_t leaf) + { + assert(n < MAX_SIZE); + m_data[0] = reinterpret_cast(leaf); + for (uintptr_t i = 1; i <= n; ++i) { + m_data[i] = reinterpret_cast(i); + } + + m_size = n + 1; + m_skip = 0; + } + static void setup(); static void print(); private: static int unwind(void** data); - + private: int m_size = 0; int m_skip = 0; diff --git a/src/track/trace_libunwind.cpp b/src/track/trace_libunwind.cpp index c76337c7..b52fda23 100644 --- a/src/track/trace_libunwind.cpp +++ b/src/track/trace_libunwind.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2014-2019 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2019 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ /** * @brief A libunwind based backtrace. @@ -24,10 +12,11 @@ #include "util/libunwind_config.h" -#define UNW_LOCAL_ONLY -#include +#include +#include -#include +#define UNW_LOCAL_ONLY 1 +#include void Trace::print() { @@ -60,9 +49,12 @@ void Trace::print() void Trace::setup() { // configure libunwind for better speed +#if LIBUNWIND_HAS_UNW_CACHE_PER_THREAD if (unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD)) { fprintf(stderr, "WARNING: Failed to enable per-thread libunwind caching.\n"); } +#endif + #if LIBUNWIND_HAS_UNW_SET_CACHE_SIZE if (unw_set_cache_size(unw_local_addr_space, 1024, 0)) { fprintf(stderr, "WARNING: Failed to set libunwind cache size.\n"); diff --git a/src/track/trace_unwind_tables.cpp b/src/track/trace_unwind_tables.cpp index 0ccdd841..d35cb2be 100644 --- a/src/track/trace_unwind_tables.cpp +++ b/src/track/trace_unwind_tables.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2019 Volodymyr Nikolaichuk - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2019 Volodymyr Nikolaichuk + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ /** * @brief A unwind-tables based backtrace. diff --git a/src/track/tracetree.h b/src/track/tracetree.h index 83c83bab..2a03d882 100644 --- a/src/track/tracetree.h +++ b/src/track/tracetree.h @@ -1,20 +1,8 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TRACETREE_H #define TRACETREE_H diff --git a/src/util/config.h.cmake b/src/util/config.h.cmake index 6c9098a5..c8d8264c 100644 --- a/src/util/config.h.cmake +++ b/src/util/config.h.cmake @@ -1,20 +1,8 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef HEAPTRACK_CONFIG_H #define HEAPTRACK_CONFIG_H diff --git a/src/util/indices.h b/src/util/indices.h index 8f21bba9..0c636355 100644 --- a/src/util/indices.h +++ b/src/util/indices.h @@ -1,25 +1,13 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef INDICES_H #define INDICES_H -#include +#include // sadly, C++ doesn't yet have opaque typedefs template @@ -61,6 +49,11 @@ struct Index { return index == o.index; } + + void operator++() + { + ++index; + } }; template @@ -105,9 +98,17 @@ struct IndexHasher namespace std { template <> +struct hash : IndexHasher +{ +}; +template <> struct hash : IndexHasher { }; +template <> +struct hash : IndexHasher +{ +}; } #endif // INDICES_H diff --git a/src/util/libunwind_config.h.cmake b/src/util/libunwind_config.h.cmake index 40c6c942..a8fe480a 100644 --- a/src/util/libunwind_config.h.cmake +++ b/src/util/libunwind_config.h.cmake @@ -1,20 +1,8 @@ /* - * Copyright 2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef LIBUNWIND_CONFIG_H #define LIBUNWIND_CONFIG_H @@ -29,5 +17,7 @@ #cmakedefine01 LIBUNWIND_HAS_UNW_SET_CACHE_SIZE +#cmakedefine01 LIBUNWIND_HAS_UNW_CACHE_PER_THREAD + #endif // LIBUNWIND_CONFIG_H diff --git a/src/util/linereader.h b/src/util/linereader.h index 3699656c..a8af47c3 100644 --- a/src/util/linereader.h +++ b/src/util/linereader.h @@ -1,24 +1,13 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef LINEREADER_H #define LINEREADER_H +#include #include #include @@ -115,8 +104,28 @@ class LineReader return readHex(hex); } + void setExpectedSizedStrings(bool expectSizedStrings) + { + m_expectSizedStrings = expectSizedStrings; + } + bool operator>>(std::string& str) { + if (m_expectSizedStrings) { + uint64_t size = 0; + if (!(*this >> size) || size > static_cast(std::distance(m_it, m_line.cend()))) { + return false; + } + auto start = m_it; + m_it += size; + str.assign(start, m_it); + if (m_it != m_line.cend()) { + // eat trailing whitespace + ++m_it; + } + return true; + } + auto it = m_it; const auto end = m_line.cend(); while (it != end && *it != ' ') { @@ -149,6 +158,7 @@ class LineReader } private: + bool m_expectSizedStrings = false; std::string m_line; std::string::const_iterator m_it; }; diff --git a/src/util/linewriter.h b/src/util/linewriter.h index 24da74e9..392ef65d 100644 --- a/src/util/linewriter.h +++ b/src/util/linewriter.h @@ -1,20 +1,8 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef LINEWRITER_H #define LINEWRITER_H @@ -27,8 +15,8 @@ #include #include #include -#include #include +#include #include #include @@ -115,6 +103,20 @@ class LineWriter bool write(const std::string& line) { const auto length = line.length(); + + { + // first write the size of the string + constexpr const int maxHexCharsForSize = 16 + 1; // 2^64 == 16^16 + 1 space + if (availableSpace() < maxHexCharsForSize && !flush()) + return false; + + const auto start = out(); + auto end = writeHexNumber(start, length); + *end = ' '; + ++end; + bufferSize += (end - start); + } + if (availableSpace() < length) { if (!flush()) { return false; @@ -122,12 +124,12 @@ class LineWriter if (availableSpace() < length) { int ret = 0; do { - ret = ::write(fd, line.c_str(), length); + ret = ::write(fd, line.data(), length); } while (ret < 0 && errno == EINTR); return ret >= 0; } } - memcpy(out(), line.c_str(), length); + memcpy(out(), line.data(), length); bufferSize += length; return true; } diff --git a/src/util/macroutils.h b/src/util/macroutils.h new file mode 100644 index 00000000..eb9a7bfe --- /dev/null +++ b/src/util/macroutils.h @@ -0,0 +1,14 @@ +/* + SPDX-FileCopyrightText: 2023 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#pragma once + +// TODO: c++17 use [[maybe_unused]] +#ifdef __GNUC__ +#define POTENTIALLY_UNUSED __attribute__((unused)) +#else +#define POTENTIALLY_UNUSED +#endif diff --git a/src/util/pointermap.h b/src/util/pointermap.h index a2280106..c3e4c9c5 100644 --- a/src/util/pointermap.h +++ b/src/util/pointermap.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef POINTERMAP_H #define POINTERMAP_H @@ -22,12 +10,10 @@ #include #include #include -#include -#include -#include #include -#include +#include +#include #include "indices.h" @@ -46,6 +32,14 @@ struct IndexedAllocationInfo } }; +// see: https://stackoverflow.com/a/2595226/35250 +template +inline void hashCombine(std::size_t& seed, const T& v) +{ + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + namespace std { template <> struct hash @@ -53,8 +47,8 @@ struct hash size_t operator()(const IndexedAllocationInfo& info) const { size_t seed = 0; - boost::hash_combine(seed, info.size); - boost::hash_combine(seed, info.traceIndex.index); + hashCombine(seed, info.size); + hashCombine(seed, info.traceIndex.index); // allocationInfoIndex not hashed to allow to look it up return seed; } @@ -81,7 +75,7 @@ struct AllocationInfoSet return true; } } - std::unordered_set set; + tsl::robin_set set; }; /** @@ -129,7 +123,7 @@ class PointerMap if (mapIt == map.end()) { mapIt = map.insert(mapIt, std::make_pair(pointer.big, Indices())); } - auto& indices = mapIt->second; + auto& indices = mapIt.value(); auto pageIt = std::lower_bound(indices.smallPtrParts.begin(), indices.smallPtrParts.end(), pointer.small); auto allocationIt = indices.allocationIndices.begin() + distance(indices.smallPtrParts.begin(), pageIt); if (pageIt == indices.smallPtrParts.end() || *pageIt != pointer.small) { @@ -148,7 +142,7 @@ class PointerMap if (mapIt == map.end()) { return {{}, false}; } - auto& indices = mapIt->second; + auto& indices = mapIt.value(); auto pageIt = std::lower_bound(indices.smallPtrParts.begin(), indices.smallPtrParts.end(), pointer.small); if (pageIt == indices.smallPtrParts.end() || *pageIt != pointer.small) { return {{}, false}; @@ -169,7 +163,7 @@ class PointerMap std::vector smallPtrParts; std::vector allocationIndices; }; - std::unordered_map map; + tsl::robin_map map; }; #endif // POINTERMAP_H diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index f12a89b9..a2b9539f 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -1,20 +1,15 @@ -if (ECM_FOUND) - include(ECMEnableSanitizers) -endif() set(CMAKE_BUILD_TYPE Debug) configure_file(tst_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/tst_config.h @ONLY) include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../ ${CMAKE_CURRENT_SOURCE_DIR}/../../src + ${CMAKE_CURRENT_BINARY_DIR}/../../src/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/track ) -add_definitions(-DCATCH_CONFIG_MAIN) - -add_executable(tst_trace tst_trace.cpp) -target_link_libraries(tst_trace heaptrack_unwind) -add_test(NAME tst_trace COMMAND tst_trace) if ("${Boost_FILESYSTEM_FOUND}" AND "${Boost_SYSTEM_FOUND}") if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") @@ -23,12 +18,34 @@ if ("${Boost_FILESYSTEM_FOUND}" AND "${Boost_SYSTEM_FOUND}") include_directories( ${Boost_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR}/../../src/ - ${CMAKE_CURRENT_SOURCE_DIR}/../../src/track ) +endif() + +# tst_inject isn't asan-safe, so include it before we enable sanitizers +add_subdirectory(no_asan) + +if (ECM_FOUND) + include(ECMEnableSanitizers) +endif() + +add_executable(tst_trace tst_trace.cpp ../../src/interpret/dwarfdiecache.cpp) +set_target_properties(tst_trace PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") +target_link_libraries(tst_trace + PRIVATE + heaptrack_unwind + Threads::Threads + ${LIBDW_LIBRARIES} + tsl::robin_map +) +target_include_directories(tst_trace PRIVATE ${LIBDW_INCLUDE_DIRS} ) + +add_test(NAME tst_trace COMMAND tst_trace) + +if ("${Boost_FILESYSTEM_FOUND}" AND "${Boost_SYSTEM_FOUND}") add_executable(tst_libheaptrack tst_libheaptrack.cpp ../../src/track/libheaptrack.cpp) + set_target_properties(tst_libheaptrack PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") target_link_libraries(tst_libheaptrack LINK_PRIVATE ${CMAKE_DL_LIBS} @@ -42,31 +59,25 @@ if ("${Boost_FILESYSTEM_FOUND}" AND "${Boost_SYSTEM_FOUND}") add_test(NAME tst_libheaptrack COMMAND tst_libheaptrack) add_executable(tst_io tst_io.cpp) + set_target_properties(tst_io PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") target_link_libraries(tst_io ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ) add_test(NAME tst_io COMMAND tst_io) - - find_package(Qt5 5.2.0 CONFIG OPTIONAL_COMPONENTS Test) - if (Qt5Test_FOUND) - add_executable(tst_parser tst_parser.cpp) - target_link_libraries(tst_parser - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - heaptrack_gui_private - Qt5::Test - ) - add_test(NAME tst_parser COMMAND tst_parser) + if (TARGET heaptrack_gui_private) + find_package(Qt${QT_VERSION_MAJOR} ${QT_MIN_VERSION} CONFIG OPTIONAL_COMPONENTS Test) + if (Qt${QT_VERSION_MAJOR}Test_FOUND) + add_executable(tst_parser tst_parser.cpp) + set_target_properties(tst_parser PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_link_libraries(tst_parser + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + heaptrack_gui_private + Qt${QT_VERSION_MAJOR}::Test + ) + add_test(NAME tst_parser COMMAND tst_parser) + endif() endif() - - add_executable(tst_inject tst_inject.cpp) - target_link_libraries(tst_inject - ${CMAKE_DL_LIBS} - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ) - add_test(NAME tst_inject COMMAND tst_inject) - endif() diff --git a/tests/auto/heaptrack.embedded_lsan_suppressions.84207.zst b/tests/auto/heaptrack.embedded_lsan_suppressions.84207.zst new file mode 100644 index 00000000..87b21502 Binary files /dev/null and b/tests/auto/heaptrack.embedded_lsan_suppressions.84207.zst differ diff --git a/tests/auto/heaptrack.heaptrack_gui.99454.zst b/tests/auto/heaptrack.heaptrack_gui.99454.zst new file mode 100644 index 00000000..debe4f17 Binary files /dev/null and b/tests/auto/heaptrack.heaptrack_gui.99454.zst differ diff --git a/tests/auto/heaptrack.heaptrack_gui.99529.zst b/tests/auto/heaptrack.heaptrack_gui.99529.zst new file mode 100644 index 00000000..2b37feb0 Binary files /dev/null and b/tests/auto/heaptrack.heaptrack_gui.99529.zst differ diff --git a/tests/auto/no_asan/CMakeLists.txt b/tests/auto/no_asan/CMakeLists.txt new file mode 100644 index 00000000..1aed05d8 --- /dev/null +++ b/tests/auto/no_asan/CMakeLists.txt @@ -0,0 +1,10 @@ +if ("${Boost_FILESYSTEM_FOUND}" AND "${Boost_SYSTEM_FOUND}") + add_executable(tst_inject tst_inject.cpp) + set_target_properties(tst_inject PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_link_libraries(tst_inject + ${CMAKE_DL_LIBS} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ) + add_test(NAME tst_inject COMMAND tst_inject) +endif() diff --git a/tests/auto/tst_inject.cpp b/tests/auto/no_asan/tst_inject.cpp similarity index 70% rename from tests/auto/tst_inject.cpp rename to tests/auto/no_asan/tst_inject.cpp index d1fc629d..a0f20fe7 100644 --- a/tests/auto/tst_inject.cpp +++ b/tests/auto/no_asan/tst_inject.cpp @@ -1,22 +1,11 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "3rdparty/catch.hpp" + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "3rdparty/doctest.h" #include "tempfile.h" #include "tst_config.h" @@ -87,7 +76,7 @@ void runInjectTest(Load load, Unload unload) } } -TEST_CASE ("inject via dlopen", "[inject]") { +TEST_CASE ("inject via dlopen") { runInjectTest( []() -> void* { dlerror(); // clear error @@ -100,13 +89,32 @@ TEST_CASE ("inject via dlopen", "[inject]") { [](void* handle) { dlclose(handle); }); } +#ifdef __USE_GNU +TEST_CASE ("inject via dlmopen") { + runInjectTest( + []() -> void* { + dlerror(); // clear error + auto* handle = dlmopen(LM_ID_BASE, HEAPTRACK_LIB_INJECT_SO, RTLD_NOW); + if (!handle) { + std::cerr << "DLMOPEN FAILED: " << dlerror() << std::endl; + } + return handle; + }, + [](void* handle) { dlclose(handle); }); +} +#endif + extern "C" { __attribute__((weak)) void* __libc_dlopen_mode(const char* filename, int flag); __attribute__((weak)) int __libc_dlclose(void* handle); } -TEST_CASE ("inject via libc", "[inject]") { - REQUIRE(__libc_dlopen_mode); +TEST_CASE ("inject via libc") { + if (!__libc_dlopen_mode) { + INFO("__libc_dlopen_mode symbol not available"); + return; + } + runInjectTest([]() { return __libc_dlopen_mode(HEAPTRACK_LIB_INJECT_SO, 0x80000000 | 0x002); }, [](void* handle) { __libc_dlclose(handle); }); } diff --git a/tests/auto/suppressions.txt b/tests/auto/suppressions.txt new file mode 100644 index 00000000..8ff82877 --- /dev/null +++ b/tests/auto/suppressions.txt @@ -0,0 +1,10 @@ +# this is a comment + +# as shown above, we can deal with empty lines +this line is invalid + +leak:QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate +# whitespace is trimmed + leak:corelib/codecs/qicucodec.cpp +# we can wildcard-match and anchor +leak:^/lib*/ld-linux-*.so.2$ diff --git a/tests/auto/tempfile.h b/tests/auto/tempfile.h index 54fdce58..df0dd502 100644 --- a/tests/auto/tempfile.h +++ b/tests/auto/tempfile.h @@ -1,20 +1,8 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TEMPFILE_H #define TEMPFILE_H diff --git a/tests/auto/tst_config.h.in b/tests/auto/tst_config.h.in index 32206d12..bd01f0cd 100644 --- a/tests/auto/tst_config.h.in +++ b/tests/auto/tst_config.h.in @@ -1,20 +1,8 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #define HEAPTRACK_LIB_DIR "@PROJECT_BINARY_DIR@/@LIB_INSTALL_DIR@/heaptrack" #define HEAPTRACK_LIB_INJECT_SO HEAPTRACK_LIB_DIR "/libheaptrack_inject.so" diff --git a/tests/auto/tst_io.cpp b/tests/auto/tst_io.cpp index db825d0b..8e5e6374 100644 --- a/tests/auto/tst_io.cpp +++ b/tests/auto/tst_io.cpp @@ -1,22 +1,11 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "3rdparty/catch.hpp" + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "3rdparty/doctest.h" #include "util/linereader.h" #include "util/linewriter.h" @@ -32,7 +21,7 @@ constexpr uint64_t operator"" _u64(unsigned long long v) return static_cast(v); } -TEST_CASE ("write data", "[write]") { +TEST_CASE ("write data") { TempFile file; REQUIRE(file.open()); @@ -57,34 +46,37 @@ TEST_CASE ("write data", "[write]") { REQUIRE(file.readContents() == expectedContents); } -TEST_CASE ("buffered write", "[write]") { +TEST_CASE ("buffered write") { TempFile file; REQUIRE(file.open()); LineWriter writer(file.fd); REQUIRE(writer.canWrite()); - string expectedContents; + ostringstream expectedContents; for (unsigned i = 0; i < 10000; ++i) { REQUIRE(writer.write("%d %x\n", 42, 42)); - expectedContents += "42 2a\n"; + expectedContents << "42 2a\n"; if (i % 1000 == 0) { const string longString(LineWriter::BUFFER_CAPACITY * 2, '*'); REQUIRE(writer.write(longString)); - expectedContents += longString; + expectedContents << std::hex << longString.size() << ' ' << longString; } } for (unsigned i = 0; i < LineWriter::BUFFER_CAPACITY * 2; ++i) { const string longString(i, '*'); REQUIRE(writer.write(longString)); - expectedContents += longString; + expectedContents << std::hex << longString.size() << ' ' << longString; } - REQUIRE(expectedContents.size() > LineWriter::BUFFER_CAPACITY); + + expectedContents.flush(); + + REQUIRE(expectedContents.str().size() > LineWriter::BUFFER_CAPACITY); REQUIRE(writer.flush()); - REQUIRE(file.readContents() == expectedContents); + REQUIRE(file.readContents() == expectedContents.str()); } -TEST_CASE ("buffered writeHex", "[write]") { +TEST_CASE ("buffered writeHex") { TempFile file; REQUIRE(file.open()); @@ -101,7 +93,7 @@ TEST_CASE ("buffered writeHex", "[write]") { REQUIRE(file.readContents() == expectedContents); } -TEST_CASE ("write flush", "[write]") { +TEST_CASE ("write flush") { TempFile file; REQUIRE(file.open()); @@ -124,7 +116,7 @@ TEST_CASE ("write flush", "[write]") { REQUIRE(file.readContents() == data1 + data2); } -TEST_CASE ("read line 64bit", "[read]") { +TEST_CASE ("read line 64bit") { const string contents = "m /tmp/KDevelop-5.2.1-x86_64/usr/lib/libKF5Completion.so.5 7f48beedc00 0 36854 236858 2700\n"; stringstream stream(contents); @@ -136,12 +128,12 @@ TEST_CASE ("read line 64bit", "[read]") { REQUIRE(reader.mode() == 'm'); string module; - REQUIRE(reader >> module); + REQUIRE((reader >> module)); REQUIRE(module == "/tmp/KDevelop-5.2.1-x86_64/usr/lib/libKF5Completion.so.5"); for (auto expected : {0x7f48beedc00_u64, 0x0_u64, 0x36854_u64, 0x236858_u64, 0x2700_u64}) { uint64_t addr = 0; - REQUIRE(reader >> addr); + REQUIRE((reader >> addr)); REQUIRE(addr == expected); } @@ -150,7 +142,7 @@ TEST_CASE ("read line 64bit", "[read]") { REQUIRE(!(reader >> module)); } -TEST_CASE ("read line 32bit", "[read]") { +TEST_CASE ("read line 32bit") { const string contents = "t 4 3\n" "a 11c00 4\n" "+ 0\n"; @@ -161,18 +153,18 @@ TEST_CASE ("read line 32bit", "[read]") { REQUIRE(reader.getLine(stream)); REQUIRE(reader.line() == "t 4 3"); REQUIRE(reader.mode() == 't'); - REQUIRE(reader >> idx); + REQUIRE((reader >> idx)); REQUIRE(idx == 0x4); - REQUIRE(reader >> idx); + REQUIRE((reader >> idx)); REQUIRE(idx == 0x3); REQUIRE(!(reader >> idx)); REQUIRE(reader.getLine(stream)); REQUIRE(reader.line() == "a 11c00 4"); REQUIRE(reader.mode() == 'a'); - REQUIRE(reader >> idx); + REQUIRE((reader >> idx)); REQUIRE(idx == 0x11c00); - REQUIRE(reader >> idx); + REQUIRE((reader >> idx)); REQUIRE(idx == 0x4); REQUIRE(!(reader >> idx)); @@ -180,7 +172,7 @@ TEST_CASE ("read line 32bit", "[read]") { REQUIRE(reader.line() == "+ 0"); REQUIRE(reader.mode() == '+'); - REQUIRE(reader >> idx); + REQUIRE((reader >> idx)); REQUIRE(idx == 0x0); REQUIRE(!(reader >> idx)); } diff --git a/tests/auto/tst_libheaptrack.cpp b/tests/auto/tst_libheaptrack.cpp index 35a3d8f5..f64db071 100644 --- a/tests/auto/tst_libheaptrack.cpp +++ b/tests/auto/tst_libheaptrack.cpp @@ -1,32 +1,22 @@ /* - * Copyright 2018 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "3rdparty/catch.hpp" + SPDX-FileCopyrightText: 2018 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "3rdparty/doctest.h" + #include "track/libheaptrack.h" #include "util/linewriter.h" -#include #include +#include -#include #include -#include #include +#include +#include #include "tempfile.h" @@ -39,26 +29,28 @@ using namespace std; TEST_CASE ("api") { TempFile tmp; // opened/closed by heaptrack_init - SECTION ("init") { - heaptrack_init(tmp.fileName.c_str(), - []() { - REQUIRE(!initBeforeCalled); - REQUIRE(!initAfterCalled); - REQUIRE(!stopCalled); - initBeforeCalled = true; - }, - [](LineWriter& out) { - REQUIRE(initBeforeCalled); - REQUIRE(!initAfterCalled); - REQUIRE(!stopCalled); - initAfterCalled = true; - }, - []() { - REQUIRE(initBeforeCalled); - REQUIRE(initAfterCalled); - REQUIRE(!stopCalled); - stopCalled = true; - }); + SUBCASE("init") + { + heaptrack_init( + tmp.fileName.c_str(), + []() { + REQUIRE(!initBeforeCalled); + REQUIRE(!initAfterCalled); + REQUIRE(!stopCalled); + initBeforeCalled = true; + }, + [](LineWriter& /*out*/) { + REQUIRE(initBeforeCalled); + REQUIRE(!initAfterCalled); + REQUIRE(!stopCalled); + initAfterCalled = true; + }, + []() { + REQUIRE(initBeforeCalled); + REQUIRE(initAfterCalled); + REQUIRE(!stopCalled); + stopCalled = true; + }); REQUIRE(initBeforeCalled); REQUIRE(initAfterCalled); @@ -66,40 +58,47 @@ TEST_CASE ("api") { int data[2] = {0}; - SECTION ("no-op-malloc") { + SUBCASE("no-op-malloc") + { heaptrack_malloc(0, 0); } - SECTION ("no-op-malloc-free") { + SUBCASE("no-op-malloc-free") + { heaptrack_free(0); } - SECTION ("no-op-malloc-realloc") { + SUBCASE("no-op-malloc-realloc") + { heaptrack_realloc(data, 1, 0); } - SECTION ("malloc-free") { + SUBCASE("malloc-free") + { heaptrack_malloc(data, 4); heaptrack_free(data); } - SECTION ("realloc") { + SUBCASE("realloc") + { heaptrack_malloc(data, 4); heaptrack_realloc(data, 8, data); heaptrack_realloc(data, 16, data + 1); heaptrack_free(data + 1); } - SECTION ("invalidate-cache") { + SUBCASE("invalidate-cache") + { heaptrack_invalidate_module_cache(); } - SECTION ("multi-threaded") { + SUBCASE("multi-threaded") + { const auto numThreads = min(4u, thread::hardware_concurrency()); cout << "start threads" << endl; { vector> futures; for (unsigned i = 0; i < numThreads; ++i) { - futures.emplace_back(async(launch::async, [](){ + futures.emplace_back(async(launch::async, []() { for (int i = 0; i < 10000; ++i) { heaptrack_malloc(&i, i); heaptrack_realloc(&i, i + 1, &i); @@ -114,7 +113,8 @@ TEST_CASE ("api") { cout << "threads finished" << endl; } - SECTION ("stop") { + SUBCASE("stop") + { heaptrack_stop(); REQUIRE(stopCalled); } diff --git a/tests/auto/tst_parser.cpp b/tests/auto/tst_parser.cpp index 8ef44bca..53459372 100644 --- a/tests/auto/tst_parser.cpp +++ b/tests/auto/tst_parser.cpp @@ -1,103 +1,338 @@ /* - * Copyright 2019 David Faure - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "3rdparty/catch.hpp" + SPDX-FileCopyrightText: 2019 David Faure -#include "parser.h" + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#define DOCTEST_CONFIG_IMPLEMENT +#include "3rdparty/doctest.h" + +#include "analyze/suppressions.h" #include "locationdata.h" +#include "parser.h" #include "treemodel.h" #include "tst_config.h" // for SRC_DIR +#include + #include #include -TEST_CASE ("parse sample file", "[parser]") { +std::ostream& operator<<(std::ostream& os, const QString& value) +{ + os << value.toStdString(); + return os; +} - int argc = 0; - QCoreApplication app(argc, nullptr); - Parser parser; +struct TestParser +{ + TestParser() + : spySummary(&parser, &Parser::summaryAvailable) + , spyCCD(&parser, &Parser::callerCalleeDataAvailable) + , spyBottomUp(&parser, &Parser::bottomUpDataAvailable) + , spyTopDown(&parser, &Parser::topDownDataAvailable) + , spyFinished(&parser, &Parser::finished) + { + QObject::connect(&parser, &Parser::bottomUpDataAvailable, &parser, + [this](const auto& data) { resultData = data.resultData; }); + } - qRegisterMetaType(); - QSignalSpy spyCCD(&parser, &Parser::callerCalleeDataAvailable); - QSignalSpy spyBottomUp(&parser, &Parser::bottomUpDataAvailable); - QSignalSpy spyTopDown(&parser, &Parser::topDownDataAvailable); + ~TestParser() + { + if (spyFinished.isEmpty()) + REQUIRE(spyFinished.wait(20000)); + } - parser.parse(SRC_DIR "/heaptrack.david.18594.gz", QString()); + CallerCalleeResults awaitCallerCallee() + { + if (spyCCD.isEmpty()) + REQUIRE(spyCCD.wait(20000)); - // ---- Check Caller Callee Data + auto ccr = spyCCD.at(0).at(0).value(); + REQUIRE(ccr.resultData); + REQUIRE(ccr.resultData == resultData); + return ccr; + } + + TreeData awaitBottomUp() + { + if (spyBottomUp.isEmpty()) + REQUIRE(spyBottomUp.wait(20000)); + + auto bottomUpData = spyBottomUp.at(0).at(0).value(); + REQUIRE(bottomUpData.resultData); + REQUIRE(bottomUpData.resultData == resultData); + + if (qEnvironmentVariableIntValue("HEAPTRACK_DEBUG")) { + qDebug() << "Bottom Up Data:"; + for (const RowData& row : bottomUpData.rows) { + qDebug() << symbolToString(row.symbol); + } + } + + return bottomUpData; + } + + TreeData awaitTopDown() + { + if (spyTopDown.isEmpty()) + REQUIRE(spyTopDown.wait(20000)); - if (spyCCD.isEmpty()) - REQUIRE(spyCCD.wait()); + auto topDownData = spyTopDown.at(0).at(0).value(); + REQUIRE(topDownData.resultData); + REQUIRE(topDownData.resultData == resultData); - const CallerCalleeResults ccr = spyCCD.at(0).at(0).value(); - auto ccrSymbolList = ccr.entries.keys(); - std::sort(ccrSymbolList.begin(), ccrSymbolList.end(), Symbol::FullLessThan()); - if (!qgetenv("HEAPTRACK_DEBUG").isEmpty()) { - for (const Symbol &sym : ccrSymbolList) { - qDebug() << sym.symbol << sym.binary << sym.path; + if (qEnvironmentVariableIntValue("HEAPTRACK_DEBUG")) { + qDebug() << "Top Down Data:"; + for (const RowData& row : topDownData.rows) { + qDebug() << symbolToString(row.symbol); + } } + + return topDownData; + } + + SummaryData awaitSummary() + { + if (spySummary.isEmpty()) + REQUIRE(spySummary.wait(20000)); + + return spySummary.at(0).at(0).value(); + } + + Parser parser; + std::shared_ptr resultData; + + QString symbolToString(const Symbol& sym) const + { + const auto module = resultData->string(sym.moduleId); + return resultData->string(sym.functionId) + '|' + Util::basename(module) + '|' + module; } + QList sortedSymbols(const CallerCalleeResults& ccr) const + { + auto ccrSymbolList = ccr.entries.keys(); + std::sort(ccrSymbolList.begin(), ccrSymbolList.end(), [&](const Symbol& lhs, const Symbol& rhs) { + // keep unresolved functions up front + auto sortable = [&](const Symbol& symbol) { + auto str = [&](StringIndex stringId) { return ccr.resultData->string(stringId); }; + return std::make_tuple(str(symbol.functionId), str(symbol.moduleId)); + }; + return sortable(lhs) < sortable(rhs); + }); + if (qEnvironmentVariableIntValue("HEAPTRACK_DEBUG")) { + qDebug() << "Sorted Symbols"; + int i = 0; + for (const Symbol& sym : ccrSymbolList) { + qDebug() << i++ << symbolToString(sym); + } + } + return ccrSymbolList; + } + +private: + QSignalSpy spySummary; + QSignalSpy spyCCD; + QSignalSpy spyBottomUp; + QSignalSpy spyTopDown; + QSignalSpy spyFinished; +}; + +TEST_CASE ("heaptrack.david.18594.gz") { + TestParser parser; + + FilterParameters params; + bool parsedSuppressions = false; + params.suppressions = parseSuppressions(SRC_DIR "/suppressions.txt", &parsedSuppressions); + REQUIRE(parsedSuppressions); + + parser.parser.parse(SRC_DIR "/heaptrack.david.18594.gz", QString(), params); + + // ---- Check Caller Callee Data + + const auto ccr = parser.awaitCallerCallee(); + const auto ccrSymbolList = parser.sortedSymbols(ccr); + // Let's check a few items - auto symbolToString = [](const Symbol &sym) { return sym.symbol + '|' + sym.binary + '|' + sym.path; }; - REQUIRE(symbolToString(ccrSymbolList.at(0)) == "||"); - REQUIRE(symbolToString(ccrSymbolList.at(1)) == "|ld-linux-x86-64.so.2|/lib64/ld-linux-x86-64.so.2"); - REQUIRE(symbolToString(ccrSymbolList.at(25)) == "QByteArray::constData() const|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); + REQUIRE(parser.symbolToString(ccrSymbolList.at(0)) == "||"); + REQUIRE(parser.symbolToString(ccrSymbolList.at(1)) + == "|ld-linux-x86-64.so.2|/lib64/ld-linux-x86-64.so.2"); + REQUIRE(parser.symbolToString(ccrSymbolList.at(25)) + == "QByteArray::constData() const|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); const int lastIndx = ccrSymbolList.size() - 1; - REQUIRE(symbolToString(ccrSymbolList.at(lastIndx)) == "~QVarLengthArray|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); + REQUIRE(parser.symbolToString(ccrSymbolList.at(lastIndx)) + == "~QVarLengthArray|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); REQUIRE(ccr.entries.count() == 365); - REQUIRE(ccr.totalCosts.allocations == 2896); + REQUIRE(ccr.resultData->totalCosts().allocations == 2896); // ---- Check Bottom Up Data - if (spyBottomUp.isEmpty()) - REQUIRE(spyBottomUp.wait()); + const auto bottomUpData = parser.awaitBottomUp(); - const TreeData bottomUpData = spyBottomUp.at(0).at(0).value(); - if (!qgetenv("HEAPTRACK_DEBUG").isEmpty()) { - qDebug() << "Bottom Up Data:"; - for (const RowData &row : bottomUpData) { - qDebug() << symbolToString(row.symbol); - } - } - REQUIRE(bottomUpData.size() == 54); - REQUIRE(symbolToString(bottomUpData.at(0).symbol) == "|libglib-2.0.so.0|/usr/lib64/libglib-2.0.so.0"); - REQUIRE(bottomUpData.at(0).children.size() == 2); - REQUIRE(bottomUpData.at(0).cost.allocations == 17); - REQUIRE(bottomUpData.at(0).cost.peak == 2020); - REQUIRE(symbolToString(bottomUpData.at(53).symbol) == "QThreadPool::QThreadPool(QObject*)|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); + REQUIRE(bottomUpData.rows.size() == 54); + REQUIRE(parser.symbolToString(bottomUpData.rows.at(3).symbol) + == "|libglib-2.0.so.0|/usr/lib64/libglib-2.0.so.0"); + REQUIRE(bottomUpData.rows.at(3).children.size() == 2); + REQUIRE(bottomUpData.rows.at(3).cost.allocations == 17); + REQUIRE(bottomUpData.rows.at(3).cost.peak == 2020); + REQUIRE(parser.symbolToString(bottomUpData.rows.at(53).symbol) + == "QThreadPool::QThreadPool(QObject*)|libQt5Core.so.5|/d/qt/5/kde/build/qtbase/lib/libQt5Core.so.5"); // ---- Check Top Down Data - if (spyTopDown.isEmpty()) - REQUIRE(spyTopDown.wait()); + const auto topDownData = parser.awaitTopDown(); + REQUIRE(topDownData.rows.size() == 5); + REQUIRE(parser.symbolToString(topDownData.rows.at(2).symbol) + == "|ld-linux-x86-64.so.2|/lib64/ld-linux-x86-64.so.2"); + REQUIRE(topDownData.rows.at(2).children.size() == 1); + REQUIRE(topDownData.rows.at(2).cost.allocations == 15); + REQUIRE(topDownData.rows.at(2).cost.peak == 94496); - const TreeData topDownData = spyTopDown.at(0).at(0).value(); - if (!qgetenv("HEAPTRACK_DEBUG").isEmpty()) { - qDebug() << "Top Down Data:"; - for (const RowData &row : topDownData) { - qDebug() << symbolToString(row.symbol); - } - } - REQUIRE(topDownData.size() == 5); - REQUIRE(symbolToString(topDownData.at(0).symbol) == "|ld-linux-x86-64.so.2|/lib64/ld-linux-x86-64.so.2"); - REQUIRE(topDownData.at(0).children.size() == 1); - REQUIRE(topDownData.at(0).cost.allocations == 15); - REQUIRE(topDownData.at(0).cost.peak == 94496); + // ---- Check Summary + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "./david"); + REQUIRE(summary.cost.allocations == 2896); + REQUIRE(summary.cost.temporary == 729); + REQUIRE(summary.cost.leaked == 0); + REQUIRE(summary.totalLeakedSuppressed == 30463); + REQUIRE(summary.cost.peak == 996970); + REQUIRE(summary.totalTime == 80); + REQUIRE(summary.peakRSS == 76042240); + REQUIRE(summary.peakTime == 0); + REQUIRE(summary.totalSystemMemory == 16715239424); + REQUIRE(summary.fromAttached == false); +} + +TEST_CASE ("heaptrack.embedded_lsan_suppressions.84207.zst") { + TestParser parser; + + parser.parser.parse(SRC_DIR "/heaptrack.embedded_lsan_suppressions.84207.zst", QString(), {}); + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "./tests/manual/embedded_lsan_suppressions"); + REQUIRE(summary.cost.allocations == 5); + REQUIRE(summary.cost.temporary == 0); + REQUIRE(summary.cost.leaked == 5); + REQUIRE(summary.totalLeakedSuppressed == 5); + REQUIRE(summary.cost.peak == 72714); + REQUIRE(summary.totalSystemMemory == 33643876352); +} + +TEST_CASE ("heaptrack.embedded_lsan_suppressions.84207.zst without suppressions") { + TestParser parser; + + FilterParameters params; + params.disableEmbeddedSuppressions = true; + parser.parser.parse(SRC_DIR "/heaptrack.embedded_lsan_suppressions.84207.zst", QString(), params); + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "./tests/manual/embedded_lsan_suppressions"); + REQUIRE(summary.cost.allocations == 5); + REQUIRE(summary.cost.leaked == 10); + REQUIRE(summary.totalLeakedSuppressed == 0); +} + +TEST_CASE ("heaptrack.heaptrack_gui.99454.zst") { + TestParser parser; + + FilterParameters params; + params.disableBuiltinSuppressions = true; + + parser.parser.parse(SRC_DIR "/heaptrack.heaptrack_gui.99454.zst", QString(), params); + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "heaptrack_gui heaptrack.trest_c.78689.zst"); + REQUIRE(summary.cost.allocations == 278534); + REQUIRE(summary.cost.temporary == 35481); + REQUIRE(summary.cost.leaked == 1047379); + REQUIRE(summary.cost.peak == 12222213); + + const auto ccr = parser.awaitCallerCallee(); + const auto sortedSymbols = parser.sortedSymbols(ccr); + + const auto& sym = sortedSymbols[994]; + REQUIRE(parser.symbolToString(sym) == "QHashData::allocateNode(int)|libQt5Core.so.5|/usr/lib/libQt5Core.so.5"); + const auto& cost = ccr.entries[sym]; + CHECK(cost.inclusiveCost.allocations == 5214); + CHECK(cost.inclusiveCost.temporary == 0); + CHECK(cost.inclusiveCost.leaked == 32); + CHECK(cost.inclusiveCost.peak == 56152); + CHECK(cost.selfCost.allocations == 5214); + CHECK(cost.selfCost.temporary == 0); + CHECK(cost.selfCost.leaked == 32); + CHECK(cost.selfCost.peak == 56152); +} + +TEST_CASE ("heaptrack.heaptrack_gui.99529.zst") { + TestParser parser; + + FilterParameters params; + params.disableBuiltinSuppressions = true; + + parser.parser.parse(SRC_DIR "/heaptrack.heaptrack_gui.99529.zst", QString(), params); + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "heaptrack_gui heaptrack.test_c.78689.zst"); + REQUIRE(summary.cost.allocations == 315255); + REQUIRE(summary.cost.temporary == 40771); + REQUIRE(summary.cost.leaked == 1046377); + REQUIRE(summary.cost.peak == 64840134); + + const auto ccr = parser.awaitCallerCallee(); + const auto sortedSymbols = parser.sortedSymbols(ccr); + + const auto& sym = sortedSymbols[1103]; + REQUIRE(parser.symbolToString(sym) == "QHashData::allocateNode(int)|libQt5Core.so.5|/usr/lib/libQt5Core.so.5"); + const auto& cost = ccr.entries[sym]; + CHECK(cost.inclusiveCost.allocations == 5559); + CHECK(cost.inclusiveCost.temporary == 0); + CHECK(cost.inclusiveCost.leaked == 32); + CHECK(cost.inclusiveCost.peak == 68952); + CHECK(cost.selfCost.allocations == 5559); + CHECK(cost.selfCost.temporary == 0); + CHECK(cost.selfCost.leaked == 32); + CHECK(cost.selfCost.peak == 68952); +} + +TEST_CASE ("heaptrack.heaptrack_gui.{99454,99529}.zst diff") { + TestParser parser; + + parser.parser.parse(SRC_DIR "/heaptrack.heaptrack_gui.99529.zst", SRC_DIR "/heaptrack.heaptrack_gui.99454.zst", {}); + + const auto summary = parser.awaitSummary(); + REQUIRE(summary.debuggee == "heaptrack_gui heaptrack.test_c.78689.zst"); + REQUIRE(summary.cost.allocations == 36721); + REQUIRE(summary.cost.temporary == 5290); + REQUIRE(summary.cost.leaked == -1002); + REQUIRE(summary.cost.peak == 52617921); + + const auto ccr = parser.awaitCallerCallee(); + const auto sortedSymbols = parser.sortedSymbols(ccr); + + const auto& sym = sortedSymbols[545]; + REQUIRE(parser.symbolToString(sym) == "QHashData::allocateNode(int)|libQt5Core.so.5|/usr/lib/libQt5Core.so.5"); + const auto& cost = ccr.entries[sym]; + CHECK(cost.inclusiveCost.allocations == (5559 - 5214)); + CHECK(cost.inclusiveCost.temporary == 0); + CHECK(cost.inclusiveCost.leaked == 0); + CHECK(cost.inclusiveCost.peak == (68952 - 56152)); + CHECK(cost.selfCost.allocations == (5559 - 5214)); + CHECK(cost.selfCost.temporary == 0); + CHECK(cost.selfCost.leaked == 0); + CHECK(cost.selfCost.peak == ((68952 - 56152))); +} + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + qRegisterMetaType(); + KLocalizedString::setApplicationDomain("heaptrack"); + + doctest::Context context; + context.applyCommandLine(argc, argv); + + return context.run(); } diff --git a/tests/auto/tst_trace.cpp b/tests/auto/tst_trace.cpp index ebc74ecc..78f6d003 100644 --- a/tests/auto/tst_trace.cpp +++ b/tests/auto/tst_trace.cpp @@ -1,25 +1,24 @@ /* - * Copyright 2014-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "3rdparty/catch.hpp" + SPDX-FileCopyrightText: 2014-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "3rdparty/doctest.h" + #include "track/trace.h" +#include "track/tracetree.h" + +#include "interpret/dwarfdiecache.h" + +#include #include +#include +#include + +#include using namespace std; @@ -33,29 +32,54 @@ bool __attribute__((noinline)) fill(Trace& trace, int depth, int skip) } } +bool bar(Trace& trace, int depth); + +inline bool __attribute__((always_inline)) asdf(Trace& trace, int depth) +{ + return bar(trace, depth - 1); +} + +inline bool __attribute__((always_inline)) foo(Trace& trace, int depth) +{ + return asdf(trace, depth); +} + +bool __attribute__((noinline)) bar(Trace& trace, int depth) +{ + if (!depth) { + return trace.fill(0); + } else { + return foo(trace, depth); + } +} + void validateTrace(const Trace& trace, int expectedSize) { - SECTION ("validate the trace size") { + SUBCASE("validate the trace size") + { REQUIRE(trace.size() == expectedSize); REQUIRE(distance(trace.begin(), trace.end()) == trace.size()); } - SECTION ("validate trace contents") { + SUBCASE("validate trace contents") + { REQUIRE(find(trace.begin(), trace.end(), Trace::ip_t(0)) == trace.end()); } } } -TEST_CASE ("getting backtrace traces", "[trace]") { +TEST_CASE ("getting backtrace traces") { Trace trace; validateTrace(trace, 0); - SECTION ("fill without skipping") { + SUBCASE("fill without skipping") + { REQUIRE(trace.fill(0)); const auto offset = trace.size(); REQUIRE(offset > 1); validateTrace(trace, offset); - SECTION ("fill with skipping") { + SUBCASE("fill with skipping") + { for (auto skip : {0, 1, 2}) { for (int i = 0; i < 2 * Trace::MAX_SIZE; ++i) { REQUIRE(fill(trace, i, skip)); @@ -66,3 +90,175 @@ TEST_CASE ("getting backtrace traces", "[trace]") { } } } + +TEST_CASE ("tracetree indexing") { + TraceTree tree; + + std::mutex mutex; + const auto numTasks = std::thread::hardware_concurrency(); + std::vector> tasks(numTasks); + + struct IpToParent + { + uintptr_t ip; + uint32_t parentIndex; + }; + std::vector ipsToParent; + + struct IndexedTrace + { + Trace trace; + uint32_t index; + }; + std::vector traces; + + // fill the tree + for (auto i = 0u; i < numTasks; ++i) { + tasks[i] = std::async(std::launch::async, [&mutex, &tree, &ipsToParent, &traces, i]() { + Trace trace; + + const auto leaf = uintptr_t((i + 1) * 100); + + for (int k = 0; k < 100; ++k) { + uint32_t lastIndex = 0; + for (uintptr_t j = 0; j < 32; ++j) { + trace.fillTestData(j, leaf); + REQUIRE(trace.size() == j + 1); + + const std::lock_guard guard(mutex); + uint32_t lastParent = 0; + auto index = + tree.index(trace, [k, j, leaf, &lastParent, &ipsToParent](uintptr_t ip, uint32_t parentIndex) { + // for larger k, the trace is known and thus we won't hit this branch + REQUIRE(k == 0); + + REQUIRE(ip > 0); + REQUIRE((ip <= (j + 1) || ip == leaf)); + REQUIRE(((!lastParent && !parentIndex) || parentIndex > lastParent)); + REQUIRE(parentIndex <= ipsToParent.size()); + lastParent = parentIndex; + + ipsToParent.push_back({ip, parentIndex}); + return true; + }); + REQUIRE(index > lastIndex); + REQUIRE(index <= ipsToParent.size()); + + if (k == 0) { + traces.push_back({trace, index}); + } + } + } + }); + } + + // wait for threads to finish + for (auto& task : tasks) { + task.get(); + } + + // verify that we can rebuild the traces + for (const auto& trace : traces) { + uint32_t index = trace.index; + int i = 0; + while (index) { + REQUIRE(i < trace.trace.size()); + REQUIRE(index > 0); + REQUIRE(index <= ipsToParent.size()); + + auto map = ipsToParent[index - 1]; + REQUIRE(map.ip == reinterpret_cast(trace.trace[i])); + + index = map.parentIndex; + ++i; + } + } +} + +struct CallbackData +{ + Dwfl* dwfl = nullptr; + Dwfl_Module* mod = nullptr; +}; +static int dl_iterate_phdr_dwfl_report_callback(struct dl_phdr_info* info, size_t /*size*/, void* data) +{ + const char* fileName = info->dlpi_name; + if (!fileName || !fileName[0]) { + auto callbackData = reinterpret_cast(data); + callbackData->mod = dwfl_report_elf(callbackData->dwfl, "tst_trace", "/proc/self/exe", -1, info->dlpi_addr, false); + REQUIRE(callbackData->mod); + } + + return 0; +} + +TEST_CASE ("symbolizing") { + Trace trace; + + REQUIRE(bar(trace, 5)); + REQUIRE(trace.size() >= 6); + + Dwfl_Callbacks callbacks = { + &dwfl_build_id_find_elf, + &dwfl_standard_find_debuginfo, + &dwfl_offline_section_address, + nullptr, + }; + + auto dwfl = std::unique_ptr(dwfl_begin(&callbacks), &dwfl_end); + REQUIRE(dwfl); + + dwfl_report_begin(dwfl.get()); + CallbackData data = { dwfl.get(), nullptr }; + dl_iterate_phdr(&dl_iterate_phdr_dwfl_report_callback, &data); + dwfl_report_end(dwfl.get(), nullptr, nullptr); + + REQUIRE(data.mod); + + DwarfDieCache cache(data.mod); + uint j = 0; + for (uint i = 0; i < 6 + j; ++i) { + auto addr = reinterpret_cast(trace[i]); + + auto cuDie = cache.findCuDie(addr); + REQUIRE(cuDie); + + auto offset = addr - cuDie->bias(); + auto die = cuDie->findSubprogramDie(offset); + REQUIRE(die); + + auto dieName = cuDie->dieName(die->die()); + auto isDebugBuild = i == 0 && dieName == "Trace::unwind(void**)"; + if (i == 0 + j) { + if (!isDebugBuild) + REQUIRE(dieName == "Trace::fill(int)"); + } else { + REQUIRE(dieName == "bar"); + } + + auto scopes = findInlineScopes(die->die(), offset); + if (i <= 1 + j) { + REQUIRE(scopes.size() == 0); + } else { + REQUIRE(scopes.size() == 2); + + Dwarf_Files* files = nullptr; + dwarf_getsrcfiles(cuDie->cudie(), &files, nullptr); + REQUIRE(files); + + REQUIRE(cuDie->dieName(&scopes[0]) == "foo"); + auto loc = callSourceLocation(&scopes[0], files, cuDie->cudie()); + // called from bar + REQUIRE(loc.line == 52); + + REQUIRE(cuDie->dieName(&scopes[1]) == "asdf"); + loc = callSourceLocation(&scopes[1], files, cuDie->cudie()); + // called from foo + REQUIRE(loc.line == 44); + } + + if (isDebugBuild) { + ++j; + } + } +} diff --git a/tests/benchmarks/CMakeLists.txt b/tests/benchmarks/CMakeLists.txt index 9fe1f94d..d2150716 100644 --- a/tests/benchmarks/CMakeLists.txt +++ b/tests/benchmarks/CMakeLists.txt @@ -6,15 +6,35 @@ include_directories( include (CheckCXXSourceCompiles) check_cxx_source_compiles( "#include - int main() { return mallinfo().uordblks > 0; }" + int main() { return mallinfo2().uordblks > 0; }" HAVE_MALLOC_H) if (HAVE_MALLOC_H) add_executable(bench_pointermap bench_pointermap.cpp) + set_target_properties(bench_pointermap PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_link_libraries(bench_pointermap PRIVATE tsl::robin_map) + add_executable(bench_pointerhash bench_pointerhash.cpp) + set_target_properties(bench_pointerhash PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_link_libraries(bench_pointerhash PRIVATE tsl::robin_map) add_executable(measure_malloc_overhead measure_malloc_overhead.cpp) + set_target_properties(measure_malloc_overhead PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") endif() -add_executable(bench_parser bench_parser.cpp) -target_link_libraries(bench_parser sharedprint heaptrack_gui_private) +add_executable(bench_linereader bench_linereader.cpp) +set_target_properties(bench_linereader PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + +if (TARGET heaptrack_gui_private) + add_executable(bench_parser bench_parser.cpp) + set_target_properties(bench_parser PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_link_libraries(bench_parser sharedprint heaptrack_gui_private) +endif() + +if (TARGET Qt${QT_VERSION_MAJOR}::Core AND Boost_CONTAINER_FOUND) + add_executable(bench_tree bench_tree.cpp) + set_target_properties(bench_tree PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR}") + target_include_directories(bench_tree PRIVATE ${Boost_INCLUDE_DIRS}) + target_link_libraries(bench_tree Qt${QT_VERSION_MAJOR}::Core + ${Boost_CONTAINER_LIBRARY}) +endif() diff --git a/tests/benchmarks/bench_linereader.cpp b/tests/benchmarks/bench_linereader.cpp new file mode 100644 index 00000000..6ba5c2d8 --- /dev/null +++ b/tests/benchmarks/bench_linereader.cpp @@ -0,0 +1,37 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include + +#include +#include +#include + +int main() +{ + std::string contents; + contents.reserve(5400000); + for (int i = 0; i < 100000; ++i) { + contents.append("0 1 2 3\n"); + contents.append("102 345 678 9ab\n"); + contents.append("102345 6789ab cdef01 23456789\n"); + } + + uint64_t ret = 0; + for (int i = 0; i < 1000; ++i) { + std::istringstream in(contents); + LineReader reader; + while (reader.getLine(in)) { + uint64_t hex; + while (reader.readHex(hex)) { + ret += hex; + } + } + } + + std::cout << ret << '\n'; + return 0; +} diff --git a/tests/benchmarks/bench_parser.cpp b/tests/benchmarks/bench_parser.cpp index 35038f2a..560f3c31 100644 --- a/tests/benchmarks/bench_parser.cpp +++ b/tests/benchmarks/bench_parser.cpp @@ -1,39 +1,75 @@ /* - * Copyright 2019 David Faure - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2019 David Faure + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "parser.h" +#include "analyze/suppressions.h" + +#include #include +#include int main(int argc, char** argv) { QCoreApplication app(argc, argv); - const auto args = app.arguments(); - if (args.count() <= 1) // first arg is the app name + + QCommandLineOption stopAfterOption( + QStringLiteral("stop-after"), + QStringLiteral("stop parsing after the given stage, possible values are: Summary, BottomUp, SizeHistogram, " + "TopDownAndCallerCallee, Finished"), + QStringLiteral("stage"), QStringLiteral("Finished")); + QCommandLineParser commandLineParser; + commandLineParser.addOption(stopAfterOption); + commandLineParser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("heaptrack data files to parse")); + commandLineParser.addHelpOption(); + + commandLineParser.process(app); + + const auto files = commandLineParser.positionalArguments(); + if (files.isEmpty()) return 1; qRegisterMetaType(); + qRegisterMetaType(); Parser parser; - QObject::connect(&parser, &Parser::finished, - &app, &QCoreApplication::quit); + QObject::connect(&parser, &Parser::finished, &app, &QCoreApplication::quit); + QObject::connect(&parser, &Parser::failedToOpen, &app, [&](const QString& path) { + qWarning() << "failed to open" << path; + app.exit(1); + }); + + const auto stopAfter = [&]() { + const auto str = commandLineParser.value(stopAfterOption); + if (str == QLatin1String("Summary")) { + return Parser::StopAfter::Summary; + } else if (str == QLatin1String("BottomUp")) { + return Parser::StopAfter::BottomUp; + } else if (str == QLatin1String("SizeHistogram")) { + return Parser::StopAfter::SizeHistogram; + } else if (str == QLatin1String("TopDownAndCallerCallee")) { + return Parser::StopAfter::TopDownAndCallerCallee; + } else if (str == QLatin1String("Finished")) { + return Parser::StopAfter::Finished; + } + + qWarning() << "unsupported stopAfter stage:" << str; + exit(1); + }(); + + FilterParameters params; + const auto suppressionsFile = files.value(2); + if (!suppressionsFile.isEmpty()) { + bool parsedOk = false; + params.suppressions = parseSuppressions(suppressionsFile.toStdString(), &parsedOk); + if (!parsedOk) + return 1; + } - parser.parse(args.at(1), QString()); + parser.parse(files.value(0), files.value(1), params, stopAfter); return app.exec(); } diff --git a/tests/benchmarks/bench_pointerhash.cpp b/tests/benchmarks/bench_pointerhash.cpp index 5e33b92f..30863c8c 100644 --- a/tests/benchmarks/bench_pointerhash.cpp +++ b/tests/benchmarks/bench_pointerhash.cpp @@ -1,22 +1,10 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include #include "bench_pointers.h" #include "src/util/indices.h" @@ -44,7 +32,7 @@ struct PointerHashMap return ret; } - std::unordered_map map; + tsl::robin_map map; }; int main() diff --git a/tests/benchmarks/bench_pointermap.cpp b/tests/benchmarks/bench_pointermap.cpp index 0aa0fda8..657c1d23 100644 --- a/tests/benchmarks/bench_pointermap.cpp +++ b/tests/benchmarks/bench_pointermap.cpp @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "bench_pointers.h" #include "src/util/pointermap.h" diff --git a/tests/benchmarks/bench_pointers.h b/tests/benchmarks/bench_pointers.h index 901c52d7..ebe6ee45 100644 --- a/tests/benchmarks/bench_pointers.h +++ b/tests/benchmarks/bench_pointers.h @@ -1,20 +1,8 @@ /* - * Copyright 2015-2017 Milian Wolff - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + SPDX-FileCopyrightText: 2015-2017 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef BENCH_POINTERS #define BENCH_POINTERS @@ -22,6 +10,7 @@ #include #include #include +#include #include #include @@ -31,25 +20,27 @@ template void benchPointers() { + auto randGenerator = std::mt19937(0); + uint32_t matches = 0; constexpr uint32_t NUM_POINTERS = 10000000; { std::vector pointers(NUM_POINTERS); - const auto baseline = mallinfo().uordblks; + const auto baseline = mallinfo2().uordblks; std::cerr << "allocated vector: \t" << baseline << std::endl; for (uint32_t i = 0; i < NUM_POINTERS; ++i) { pointers[i] = reinterpret_cast(malloc(1)); } - const auto allocated = (mallinfo().uordblks - baseline); + const auto allocated = (mallinfo2().uordblks - baseline); std::cerr << "allocated input pointers:\t" << allocated << std::endl; for (auto ptr : pointers) { free(reinterpret_cast(ptr)); } - std::cerr << "freed input pointers: \t" << (mallinfo().uordblks - baseline) << std::endl; + std::cerr << "freed input pointers: \t" << (mallinfo2().uordblks - baseline) << std::endl; srand(0); - std::random_shuffle(pointers.begin(), pointers.end()); + std::shuffle(pointers.begin(), pointers.end(), randGenerator); malloc_trim(0); - std::cerr << "begin actual benchmark: \t" << (mallinfo().uordblks - baseline) << std::endl; + std::cerr << "begin actual benchmark: \t" << (mallinfo2().uordblks - baseline) << std::endl; { Map map; @@ -59,11 +50,11 @@ void benchPointers() map.addPointer(ptr, index); } - const auto added = mallinfo().uordblks - baseline; + const auto added = mallinfo2().uordblks - baseline; std::cerr << "pointers added: \t" << added << " (" << (float(added) * 100.f / allocated) << "% overhead)" << std::endl; - std::random_shuffle(pointers.begin(), pointers.end()); + std::shuffle(pointers.begin(), pointers.end(), randGenerator); for (auto ptr : pointers) { AllocationInfoIndex index; index.index = static_cast(ptr); @@ -73,9 +64,9 @@ void benchPointers() } } - std::cerr << "pointers removed: \t" << mallinfo().uordblks << std::endl; + std::cerr << "pointers removed: \t" << mallinfo2().uordblks << std::endl; malloc_trim(0); - std::cerr << "trimmed: \t" << mallinfo().uordblks << std::endl; + std::cerr << "trimmed: \t" << mallinfo2().uordblks << std::endl; } } if (matches != NUM_POINTERS) { diff --git a/tests/benchmarks/bench_tree.cpp b/tests/benchmarks/bench_tree.cpp new file mode 100644 index 00000000..2633779d --- /dev/null +++ b/tests/benchmarks/bench_tree.cpp @@ -0,0 +1,213 @@ +/* + SPDX-FileCopyrightText: 2020 Milian Wolff + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "../../src/analyze/allocationdata.h" + +constexpr uint64_t MAX_TREE_DEPTH = 64; +constexpr uint64_t NO_BRANCH_DEPTH = 4; +constexpr uint64_t BRANCH_WIDTH = 8; +constexpr uint64_t NUM_TRACES = 1000000; + +using Trace = std::array; + +uint64_t generateIp(uint64_t level) +{ + if (level % NO_BRANCH_DEPTH) { + return level; + } + static std::mt19937_64 engine(0); + static std::uniform_int_distribution dist(0, BRANCH_WIDTH - 1); + return dist(engine); +} + +Trace generateTrace() +{ + Trace trace; + for (uint64_t i = 0; i < MAX_TREE_DEPTH; ++i) { + trace[i] = generateIp(i); + } + return trace; +} + +std::vector generateTraces() +{ + std::vector traces(NUM_TRACES); + std::generate(traces.begin(), traces.end(), generateTrace); + return traces; +} + +namespace Tree { +template