이 프로젝트는 이제 보관되었으며 읽기 전용입니다.
GitHub의 timemory(소스 코드)
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의 목표는 기존 C/C++ 성능 측정 및 분석 API에 적응하는 데 사용할 수 있고 애플리케이션 내에서 사용자가 임의로 확장할 수 있는 재사용 가능한 모듈식 구성 요소로 오픈 소스 성능 측정 및 분석 패키지를 만드는 것입니다. 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는 타이머부터 하드웨어 카운터, 타사 도구와의 인터페이스에 이르기까지 50개 이상의 다양한 구성 요소를 임의로 선택할 수 있는 프런트 엔드 C/C++/Fortran API 및 Python API를 제공합니다. 이는 모두 다음 nvxt_marker
papi_vector
유형 안전 도구 번들 component_tuple<wall_clock, papi_vector, nvtx_marker, user_bundle>
wall_clock
하여 툴킷 API에서 일반적으로 구축되었습니다. NVIDIA CUDA 프로파일러와 user_bundle
다운스트림 사용자가 런타임에 더 많은 구성 요소를 삽입할 수 있는 일반 구성 요소입니다.
Timemory로 작성된 성능 측정 구성 요소는 스레드 및 프로세스 수에 관계없이 임의로 확장 가능하며 프로그램 내의 여러 위치에서 다양한 측정을 혼합하는 것을 완벽하게 지원합니다. 이는 매우 상세한 수집이 가능하기 때문에 HPC에서 규모에 맞게 성능 데이터를 수집하기 위해 Timemory를 배포할 수 있는 고유한 기능을 제공합니다. 유비쿼터스 수집이 동시에 성능을 크게 저하시키고 엄청난 양의 메모리를 요구하는 프로그램 내의 특정 위치에서 발생할 수 있습니다.
Timemory는 계측 및 샘플링 도구를 함께 묶고, JSON/XML에 대한 직렬화를 지원하고, 다양한 용도로 통계를 제공하는 백엔드로 사용할 수 있습니다. 또한 사용자 정의 계측 및 샘플링 도구를 호출하기 위한 프런트 엔드로 활용될 수도 있습니다. Timemory는 일부 성능 분석 작업을 캡슐화하는 구조에 대해 추상적인 용어인 "구성 요소"를 사용합니다. 구조는 다른 도구에 대한 함수 호출을 캡슐화하고, 타이밍에 대한 타임스탬프를 기록하고, 애플리케이션에서 제공하는 로그 값을 기록하고, 코드에서 함수를 동적으로 대체하기 위한 연산자를 제공하고, 들어오는 인수 및/또는 함수에서 나가는 반환 값을 감사하거나, 단순히 다음을 제공할 수 있습니다. 링커에 의해 오버로드될 수 있는 스텁입니다.
timemory의 기본 출력 형식은 JSON과 텍스트입니다. XML과 같은 다른 출력 형식도 지원됩니다. 텍스트 형식은 사람이 읽을 수 있도록 만들어졌습니다. JSON 데이터는 분석용으로 사용되며 계층형과 평면형의 두 가지 형태로 제공됩니다. 기본 플로팅 기능은 timemory-plotting
통해 사용할 수 있지만 사용자는 Pandas 데이터 프레임의 계층적 JSON 데이터를 분석하기 위해 손도끼를 사용하는 것이 좋습니다. Hatchet은 필터링, 합집합, 덧셈, 뺄셈, dot
및 Flamegraph 형식으로의 출력, 대화형 Jupyter 노트북을 지원합니다. 현재 timemory는 Hatchet의 분석을 위해 45개 이상의 측정항목 유형을 지원합니다.
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>
wall_clock
구성 요소 인스턴스에서 start()
멤버 함수를 호출하려고 시도합니다.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
"Storage"의 호출 스택 추적과 같은 비용이 많이 드는 작업을 암시적으로 수행하지 않습니다.참고:
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
source/timemory/compat/timemory_c.h 및 source/timemory/variadic/macros.hpp에는 C에 대한 다양한 매크로가 정의되어 있습니다. 예제에서 다양한 사용법 샘플을 찾을 수 있습니다.
# 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 릴리스 이전에는 일부 C/C++ 매크로(예: TIMEMORY_AUTO_TIMER
)와 일부 Python 데코레이터 및 컨텍스트 관리자(예: timemory.util.auto_timer
를 제외하고는 timemory가 처음부터 거의 완전히 다시 작성되었습니다. 새 릴리스에서는 완전히 복제됩니다. 따라서 Timemory는 v3.0+에서 성숙한 프로젝트로 보일 수 있지만 본질적으로 여전히 첫 번째 주요 릴리스에 있습니다.
간행물에서 시간 기록을 참조하려면 다음 논문을 인용하십시오.
자세한 내용은 설명서를 참조하세요.