Этот проект теперь заархивирован и доступен только для чтения.
timemory на GitHub (исходный код)
Общая документация timemory (ReadTheDocs)
Документация по исходному коду timemory (Doxygen)
Панель тестирования timemory (CDash)
Учебники по временной памяти
Учебное пособие по ECP 2021, день 1 (YouTube)
Учебное пособие по ECP 2021, день 2 (YouTube)
Тайммори вики
GitHub | git clone https://github.com/NERSC/timemory.git |
ПиПи | pip install timemory |
Спак | spack install timemory |
Конда-Фордж | conda install -c conda-forge timemory |
Целью timemory является создание пакета для измерения и анализа производительности с открытым исходным кодом, состоящего из модульных и повторно используемых компонентов, который можно использовать для адаптации к любому существующему API измерения и анализа производительности C/C++ и который может произвольно расширяться пользователями в рамках их приложения. Timemory — это не просто еще один инструмент для профилирования, это набор инструментов для профилирования, который упрощает создание пользовательских инструментов профилирования за счет модульности, а затем использует этот набор инструментов для предоставления нескольких готовых инструментов.
Другими словами, timemory предоставляет множество готовых инструментов, библиотек и интерфейсов, но из-за своей модульности коды могут повторно использовать только отдельные части — например, классы для измерения различных временных интервалов, использования памяти и аппаратных счетчиков. - без тайммора «управление временем выполнения».
Timemory использует стандартную установку CMake. Несколько примеров установки можно найти в Wiki. Подробную информацию о параметрах CMake см. в документации по установке.
Полная документация доступна по адресу timemory.readthedocs.io. Подробная исходная документация представлена в разделе doygen полной документации. Учебные пособия доступны по адресу github.com/NERSC/timemory-tutorials.
Основная цель timemory — разработка общей структуры для объединения кода мониторинга программного обеспечения (т. е. анализа производительности, отладки, журналирования) в компактный и высокоэффективный интерфейс.
Timemory возникла из-за потребности в универсальном наборе адаптеров для различных API, который предоставил несколько существующих инструментов и простой и интуитивно понятный метод создания новых инструментов. Timemory позволяет объединить детерминированные измерения производительности, статистические измерения производительности (т. е. выборку), сообщения отладки, регистрацию данных и проверку данных в одном интерфейсе для пользовательских интерфейсов мониторинга программного обеспечения для конкретных приложений, легко создавая такие инструменты, как time
, netstat
, контрольно-измерительные приборы. профилировщики, профилировщики выборки и написания реализаций для MPI-P, MPI-T, OMPT, KokkosP и т. д. Кроме того, timemory может пересылать свои маркеры нескольким сторонним профилировщикам, таким как LIKWID, Caliper, TAU, gperftools, Perfetto, VTune, Allinea-MAP, CrayPAT, Nsight-Systems, Nsight-Compute и NVProf.
Timemory предоставляет интерфейсные API C/C++/Fortran и API Python, которые позволяют произвольно выбирать более 50 различных компонентов, от таймеров до аппаратных счетчиков и интерфейсов со сторонними инструментами. Все это построено в общих чертах на основе API набора инструментов с типобезопасными наборами инструментов, таких как: component_tuple<wall_clock, papi_vector, nvtx_marker, user_bundle>
где wall_clock
— таймер настенных часов, papi_vector
— дескриптор аппаратных счетчиков, nvxt_marker
создает обозначения в профилировщики NVIDIA CUDA, а user_bundle
— это общий компонент, в который последующие пользователи могут вставлять дополнительные компоненты время выполнения.
Компоненты измерения производительности, написанные с использованием timemory, произвольно масштабируются до любого количества потоков и процессов и полностью поддерживают смешивание различных измерений в разных местах программы. Это дает уникальную возможность использовать timemory для сбора данных о производительности в масштабе HPC, поскольку сбор данных осуществляется с высокой степенью детализации. может произойти в определенных местах программы, где повсеместный сбор данных может значительно снизить производительность и потребовать непомерно большого объема памяти.
Timemory можно использовать в качестве серверной части для объединения инструментов и инструментов выборки, поддержки сериализации в JSON/XML и предоставления статистики среди других целей. Его также можно использовать в качестве интерфейса для вызова пользовательских инструментов и инструментов выборки. Timemory использует абстрактный термин «компонент» для обозначения структуры, которая инкапсулирует некоторые операции анализа производительности. Структура может инкапсулировать вызовы функций другого инструмента, записывать временные метки для синхронизации, регистрировать значения, предоставленные приложением, предоставлять оператор для динамической замены функции в коде, проверять входящие аргументы и/или исходящее возвращаемое значение из функции или просто предоставлять заглушки, которые могут быть перегружены компоновщиком.
Собственный формат вывода timemory — JSON и текст; другие форматы вывода, такие как XML, также поддерживаются. Текстовый формат предназначен для чтения человеком. Данные JSON предназначены для анализа и бывают двух видов: иерархические и плоские. Базовые возможности построения графиков доступны через timemory-plotting
но пользователям настоятельно рекомендуется использовать топор для анализа иерархических данных JSON в кадрах данных pandas. Hatchet поддерживает фильтрацию, объединения, сложение, вычитание, вывод в форматы dot
и Flamegraph, а также интерактивный блокнот Jupyter. В настоящее время timemory поддерживает более 45 типов метрик для анализа в Hatchet.
В timemory есть 4 основные категории: компоненты, операции, упаковщики и хранилище. Компоненты предоставляют информацию о том, как выполнять определенное поведение, операции предоставляют основу для запроса того, чтобы компонент выполнил операцию в сложных сценариях, упаковщики группируют компоненты в один общий дескриптор, а хранилище управляет сбором данных в течение всего срока службы приложения. Когда все четыре категории объединены, timemory фактически напоминает стандартный инструмент анализа производительности, который пассивно собирает данные и предоставляет отчеты и анализ при завершении работы приложения. Однако Timemory позволяет очень легко вычесть объем памяти из уравнения и тем самым превратить timemory в набор инструментов для индивидуального сбора данных.
tim::component::wall_clock
: простой таймер настенных часовtim::component::vtune_profiler
: простой компонент, который включает и выключает профилировщик VTune (когда VTune активно профилирует приложение)tim::component::data_tracker_integer
: связывает целочисленные значения с меткой во время выполнения приложения (например, количество использованных где-то итераций цикла)tim::component::papi_vector
: использует библиотеку PAPI для сбора значений аппаратных счетчиков.tim::component::user_bundle
: инкапсулирует массив компонентов, которыми пользователь может динамически манипулировать во время выполнения.tim::operation::start<wall_clock>
попытается вызвать функцию-член start()
в экземпляре компонента wall_clock
wall_clock
функция store(int)
? store()
?)tim::operation::start
: поручить компоненту начать сборtim::operation::sample
: поручить компоненту выполнить индивидуальное измерениеtim::operation::derive
: дополнительные данные из других компонентов, если они доступныtim::auto_tuple
tim::component_tuple
tim::component_list
tim::lightweight_tuple
auto_tuple
запускает все компоненты при создании и останавливает все компоненты при разрушении, тогда как component_tuple
требует явного запускаcomponent_tuple
выделяет все компоненты в стеке, и компоненты «всегда включены», тогда как component_list
распределяет компоненты в куче, и, таким образом, компоненты можно активировать/деактивировать во время выполнения.lightweight_tuple
неявно не выполняет никаких дорогостоящих действий, таких как отслеживание стека вызовов в «Хранилище».ПРИМЕЧАНИЕ.
tim::lightweight_tuple
— рекомендуемый пакет для тех, кто хочет использовать timemory в качестве набора инструментов для реализации пользовательских инструментов и интерфейсов.
timemory-avail
предоставляется как отдельный класс Python.time
, включающая дополнительную информацию об использовании памяти, переключении контекста и аппаратных счетчиках.nvidia-smi
timemory-python-profiler
from timemory.profiler import Profile
timemory-python-trace
from timemory.trace import Trace
timemory-python-line-profiler
from timemory.line_profiler import LineProfiler
Различные макросы определены для C в файлах source/timemory/compat/timemory_c.h и source/timemory/variadic/macros.hpp. Многочисленные примеры их использования можно найти в примерах.
# include " timemory/timemory.hpp "
namespace comp = tim::component;
using namespace tim ;
// specific set of components
using specific_t = component_tuple<comp::wall_clock, comp::cpu_clock>;
using generic_t = component_tuple<comp::user_global_bundle>;
int
main ( int argc, char ** argv)
{
// configure default settings
settings::flat_profile () = true ;
settings::timing_units () = " msec " ;
// initialize with cmd-line
timemory_init (argc, argv);
// add argparse support
timemory_argparse (&argc, &argv);
// create a region "main"
specific_t m{ " main " };
m. start ();
m. stop ();
// pause and resume collection globally
settings::enabled () = false ;
specific_t h{ " hidden " };
h. start (). stop ();
settings::enabled () = true ;
// Add peak_rss component to specific_t
mpl:: push_back_t < specific_t , comp::peak_rss> wprss{ " with peak_rss " };
// create region collecting only peak_rss
component_tuple<comp::peak_rss> oprss{ " only peak_rss " };
// convert component_tuple to a type that starts/stops upon construction/destruction
{
scope::config _scope{};
if ( true ) _scope += scope::flat{};
if ( false ) _scope += scope::timeline{};
convert_t < specific_t , auto_tuple<>> scoped{ " scoped start/stop + flat " , _scope };
// will yield auto_tuple<comp::wall_clock, comp::cpu_clock>
}
// configure the generic bundle via set of strings
runtime::configure<comp::user_global_bundle>({ " wall_clock " , " peak_rss " });
// configure the generic bundle via set of enumeration ids
runtime::configure<comp::user_global_bundle>({ TIMEMORY_WALL_CLOCK, TIMEMORY_CPU_CLOCK });
// configure the generic bundle via component instances
comp::user_global_bundle::configure<comp::page_rss, comp::papi_vector>();
generic_t g{ " generic " , quirk::config<quirk::auto_start>{} };
g. stop ();
// Output the results
timemory_finalize ();
return 0 ;
}
# include " timemory/library.h "
# include " timemory/timemory.h "
int
main ( int argc, char ** argv)
{
// configure settings
int overwrite = 0 ;
int update_settings = 1 ;
// default to flat-profile
timemory_set_environ ( " TIMEMORY_FLAT_PROFILE " , " ON " , overwrite, update_settings);
// force timing units
overwrite = 1 ;
timemory_set_environ ( " TIMEMORY_TIMING_UNITS " , " msec " , overwrite, update_settings);
// initialize with cmd-line
timemory_init_library (argc, argv);
// check if inited, init with name
if (! timemory_library_is_initialized ())
timemory_named_init_library ( " ex-c " );
// define the default set of components
timemory_set_default ( " wall_clock, cpu_clock " );
// create a region "main"
timemory_push_region ( " main " );
timemory_pop_region ( " main " );
// pause and resume collection globally
timemory_pause ();
timemory_push_region ( " hidden " );
timemory_pop_region ( " hidden " );
timemory_resume ();
// Add/remove component(s) to the current set of components
timemory_add_components ( " peak_rss " );
timemory_remove_components ( " peak_rss " );
// get an identifier for a region and end it
uint64_t idx = timemory_get_begin_record ( " indexed " );
timemory_end_record (idx);
// assign an existing identifier for a region
timemory_begin_record ( " indexed/2 " , &idx);
timemory_end_record (idx);
// create region collecting a specific set of data
timemory_begin_record_enum ( " enum " , &idx, TIMEMORY_PEAK_RSS, TIMEMORY_COMPONENTS_END);
timemory_end_record (idx);
timemory_begin_record_types ( " types " , &idx, " peak_rss " );
timemory_end_record (idx);
// replace current set of components and then restore previous set
timemory_push_components ( " page_rss " );
timemory_pop_components ();
timemory_push_components_enum ( 2 , TIMEMORY_WALL_CLOCK, TIMEMORY_CPU_CLOCK);
timemory_pop_components ();
// Output the results
timemory_finalize_library ();
return 0 ;
}
program fortran_example
use timemory
use iso_c_binding, only : C_INT64_T
implicit none
integer (C_INT64_T) :: idx
! initialize with explicit name
call timemory_init_library( " ex-fortran " )
! initialize with name extracted from get_command_argument( 0 , ...)
! call timemory_init_library( " " )
! define the default set of components
call timemory_set_default( " wall_clock, cpu_clock " )
! Start region " main "
call timemory_push_region( " main " )
! Add peak_rss to the current set of components
call timemory_add_components( " peak_rss " )
! Nested region " inner " nested under " main "
call timemory_push_region( " inner " )
! End the " inner " region
call timemory_pop_region( " inner " )
! remove peak_rss
call timemory_remove_components( " peak_rss " )
! begin a region and get an identifier
idx = timemory_get_begin_record( " indexed " )
! replace current set of components
call timemory_push_components( " page_rss " )
! Nested region " inner " with only page_rss components
call timemory_push_region( " inner (pushed) " )
! Stop " inner " region with only page_rss components
call timemory_pop_region( " inner (pushed) " )
! restore previous set of components
call timemory_pop_components()
! end the " indexed " region
call timemory_end_record(idx)
! End " main "
call timemory_pop_region( " main " )
! Output the results
call timemory_finalize_library()
end program fortran_example
from timemory . bundle import marker
@ marker ([ "cpu_clock" , "peak_rss" ])
def foo ():
pass
from timemory . profiler import profile
def bar ():
with profile ([ "wall_clock" , "cpu_util" ]):
foo ()
from timemory . component import WallClock
def spam ():
wc = WallClock ( "spam" )
wc . start ()
bar ()
wc . stop ()
data = wc . get ()
print ( data )
import argparse
parser = argparse . ArgumentParser ( "example" )
# ...
timemory . add_arguments ( parser )
args = parser . parse_args ()
from timemory . storage import WallClockStorage
# data for current rank
data = WallClockStorage . get ()
# combined data on rank zero but all ranks must call it
dmp_data = WallClockStorage . dmp_get ()
Timemory возник как очень простой инструмент для записи измерений времени и памяти (отсюда и название) на C, C++ и Python и до версии 3.0.0 поддерживал только три режима: фиксированный набор таймеров, пару измерений памяти, и сочетание того и другого. До выпуска 3.0.0 timemory был почти полностью переписан с нуля, за исключением некоторых макросов C/C++, например TIMEMORY_AUTO_TIMER
, а также некоторых декораторов Python и менеджера контекста, например timemory.util.auto_timer
, поведение которых можно было изменить. быть полностью воспроизведено в новой версии. Таким образом, хотя может показаться, что timemory является зрелым проектом версии 3.0+, по сути, он все еще находится в своей первой основной версии.
Для ссылки на таймморию в публикации цитируйте следующую статью:
Для получения дополнительной информации обратитесь к документации.