pax_global_header00006660000000000000000000000064141566601650014524gustar00rootroot0000000000000052 comment=01cc9d0afe4f258887b5e1e54f322ce2a4a6ac9b LiTL-litl-0.2/000077500000000000000000000000001415666016500131335ustar00rootroot00000000000000LiTL-litl-0.2/AUTHORS000066400000000000000000000002371415666016500142050ustar00rootroot00000000000000Main contributors: - François Trahay -- Project Leader - Roman Iakymchuk -- Developer LiTL-litl-0.2/CMakeLists.txt000066400000000000000000000020061415666016500156710ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.1) project(LiTL VERSION 0.2.0 LANGUAGES C DESCRIPTION "LiTL is a tracing library" HOMEPAGE_URL https://github.com/trahay/LiTL ) # include CMake modules include(CheckLibraryExists) option(ENABLE_GETTID "Use syscall(SYS_gettid) to get the thread ID instead of pthread_self(). This however costs a system call for each trace entry" OFF) option(FORCE_32BITS "Build LiTL in 32-bit mode" OFF) CHECK_LIBRARY_EXISTS(rt clock_gettime "" librt_exist) if (NOT librt_exist) message(FATAL_ERROR "librt was not found.") endif() CHECK_LIBRARY_EXISTS(m ceil "" libm_exist) if (NOT libm_exist) message(FATAL_ERROR "libm was not found.") endif() set (INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig") # Subdirectory add_subdirectory (src) add_subdirectory (utils) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/litl.pc.in ${CMAKE_CURRENT_BINARY_DIR}/litl.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/litl.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}") LiTL-litl-0.2/COPYING000066400000000000000000000024221415666016500141660ustar00rootroot00000000000000Copyright (c) 2013, Télécom SudParis All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 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. 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. LiTL-litl-0.2/COPYRIGHT000066400000000000000000000024221415666016500144260ustar00rootroot00000000000000Copyright (c) 2013, Télécom SudParis All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 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. 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. LiTL-litl-0.2/ChangeLog000066400000000000000000000006711415666016500147110ustar00rootroot00000000000000Version 0.1 ---------- * The first release supports: * Recording events only on the user level; * Recording events with up to 10 parameters; * Recording events when parameters are saved as a string, e.g. for error msgs; * Thread-safety through pthread_mutex; * Analyzing the trace (evnt_read); * Testing libevnt through testing recording and analyzing; * The choice of the optimal buffer size for both recording and analyzing events. LiTL-litl-0.2/NEWS000066400000000000000000000000001415666016500136200ustar00rootroot00000000000000LiTL-litl-0.2/README000066400000000000000000000037261415666016500140230ustar00rootroot00000000000000LiTL: Lightweight Trace Library ============================================= LiTL is a lightweight tool for recording events during the execution of scientific high-performance applications. LiTL is designed to record events on the user level only. Therefore, it consumes much less resources (CPU time, memory, and the disk space) as the alternative tools, e.g. FxT that gather events on both user and kernel levels. As a result, LiTL is well-suited for recording events on embedded systems like ARM architectures. Requirements ============================================= In order to use LiTL, the following software is needed: * autoconf 2.63; Getting LiTL ============================================= Current development version of LiTL is available via Git git clone git+ssh://fusionforge.int-evry.fr//var/lib/gforge/chroot/ scmrepos/git/litl/litl.git After getting the latest development version (from Git), './bootstrap' should be run in the root directory and only then the tool can be built. Installing LiTL ============================================= At first, to configure LiTL the following script should be invoked: $ ./configure --prefix= The configuration script contains many different options that can be set. However, we recommend to use the default settings. Once LiTL is configured, the next two commands should be executed: $ make $ make install In order to check whether LiTL was installed correctly, a set of tests can be run as $ make check Using LiTL ============================================= litl_print ---------- This tool is used to analyze trace files produced by LiTL as $ litl_print -f trace.file litl_merge ---------- This tool is used to merge severals traces into one archive as $ litl_merge -o archive.trace trace.0 trace.1 ... trace.n litl_split ---------- This tool is used to split an archive of traces into separate trace files as $ litl_split -f archive.trace -d output.dir LiTL-litl-0.2/doc/000077500000000000000000000000001415666016500137005ustar00rootroot00000000000000LiTL-litl-0.2/doc/Doxyfile.in000066400000000000000000002354261415666016500160270ustar00rootroot00000000000000# Doxyfile 1.8.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed # in front of the TAG it is preceding . # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = @PACKAGE_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @PACKAGE_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, # Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, # Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields or simple typedef fields will be shown # inline in the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO (the default), structs, classes, and unions are shown on a separate # page (for HTML and Man pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can # be an expensive process and often the same symbol appear multiple times in # the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too # small doxygen will become slower. If the cache is too large, memory is wasted. # The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid # range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 # symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. #HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if section-label ... \endif # and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. Do not use # file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @top_srcdir@/src @top_srcdir@/utils # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be ignored. # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = __ #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and # SVG. The default value is HTML-CSS, which is slower, but has the best # compatibility. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript # pieces of code that will be used on startup of the MathJax code. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. # There are two flavours of web server based search depending on the # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # searching and an index file used by the script. When EXTERNAL_SEARCH is # enabled the indexing and searching needs to be provided by external tools. # See the manual for details. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain # the search results. Doxygen ships with an example indexer (doxyindexer) and # search engine (doxysearch.cgi) which are based on the open source search # engine library Xapian. See the manual for configuration details. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will returned the search results when EXTERNAL_SEARCH is enabled. # Doxygen ships with an example search engine (doxysearch) which is based on # the open source search engine library Xapian. See the manual for configuration # details. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id # of to a relative location where the documentation can be found. # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4 will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images # or other source files which should be copied to the LaTeX output directory. # Note that the files will be copied as-is; there are no commands or markers # available. LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- # If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files # that can be used to generate PDF. GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in # front of it. If left blank docbook will be used as the default path. DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = __attribute__(x)= USE_GETTID __x86_64__ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed # in the related pages index. If set to NO, only the current project's # pages will be listed. EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES LiTL-litl-0.2/doc/Makefile.am000066400000000000000000000025651415666016500157440ustar00rootroot00000000000000EXTRA_DIST = if WITHDOC if HAVE_DOXYGEN doxyfile.stamp: $(DOXYGEN) Doxyfile echo Timestamp > doxyfile.stamp CLEANFILES = doxyfile.stamp all-local: doxyfile.stamp latex/refman.pdf latex/refman.pdf: $(MAKE) -C latex clean-local: rm -rf $(top_srcdir)/doc/man latex doxyfile.stamp install-data-local: $(INSTALL) -d $(DESTDIR)$(datadir)/doc/$(PACKAGE)/ $(INSTALL_DATA) -D $(builddir)/latex/refman.pdf \ $(DESTDIR)$(datadir)/doc/$(PACKAGE)/ uninstall-local: rm -rf $(DESTDIR)$(datadir)/doc/$(PACKAGE)/refman.pdf endif if HAVE_LATEXMK doc_DATA = user_manual.pdf docfiles = user_manual.pdf MANNAME = user_manual MANTEXSRC = $(MANNAME).tex MANAUX = $(MANNAME).aux MANPDF = $(MANNAME).pdf CLEANFILES = $(MANPDF) $(MANNAME).log $(MANNAME).idx $(MANNAME).out \ $(MANNAME).toc $(MANAUX) $(MANNAME).auxlock $(MANNAME).bbl \ $(MANNAME).blg $(MANNAME).fdb_latexmk $(MANNAME).fls header.aux $(MANPDF): $(MANTEXSRC) latexmk -pdf -pdflatex="pdflatex -interaction=nonstopmode" -bibtex $< #dist_doc_DATA = $(docfiles) endif endif #WITHDOC EXTRA_DIST += $(top_srcdir)/doc/tikz/event.recording.all.tex\ $(top_srcdir)/doc/tikz/event.storage.all.line.packed.tex\ $(top_srcdir)/doc/tikz/event.storage.trace.file.merge.tex\ $(top_srcdir)/doc/tikz/event.storage.trace.file.tex \ $(top_srcdir)/doc/references.bib LiTL-litl-0.2/doc/header.tex.in000066400000000000000000000122601415666016500162600ustar00rootroot00000000000000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FOR PRINTING \documentclass[ 11pt, a4paper, openright ]{report} \newcommand{\litl}{LiTL} \newcommand{\reporttitle}{\litl} \newcommand{\reportsubtitle}{Lightweight Trace Library @PACKAGE_VERSION@} \newcommand{\reportsubsubtitle}{User Manual} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{etex} \usepackage[utf8]{inputenc} \usepackage{pdflscape} \usepackage[T1]{fontenc} \usepackage[small,bf]{caption} \usepackage{fullpage} % for plotting \usepackage{subfigure} \usepackage{graphicx} \usepackage{color} %\usepackage{xcolor} % \definecolor{ListingsKeywordColor}{rgb}{0,0,0.4} % \definecolor{ListingsIdentifierColor}{rgb}{0,0.5,0} % \definecolor{ListingsCommentColor}{rgb}{0.4,0.4,0.4} % \definecolor{ListingsStringColor}{rgb}{0.6000,0.3333,0.7333}%{0.8,0,0} % \definecolor{ListingsRuleSepColor}{rgb}{0,0,0} % \definecolor{ListingsEmphColor}{rgb}{0,0.6667,0.6667} % \definecolor{ListingsBreakSymbolColor}{rgb}{0.780,0.082,0.522} % \definecolor{LinkColor}{rgb}{0,0,0.5} % \definecolor{UnitColor}{rgb}{0,0,0} % \definecolor{MathsVectorColor}{rgb}{0,0,0} % \definecolor{MathsMatrixColor}{rgb}{0,0,0} % \definecolor{MyGreen}{HTML}{228B22} % \definecolor{MyBlue}{HTML}{0000FF} % \colorlet{MatrixElementsLight}{gray!20!white} % \colorlet{MatrixElementsDark}{gray!40} \usepackage{tikz} \usepackage{pgfplots} \usetikzlibrary{ external, arrows, positioning, decorations.pathmorphing, 3d } \tikzexternalize \tikzsetexternalprefix{imgs/tikz/} \tikzset{ external/export=false, %Define standard arrow tip >=stealth', %Define style for boxes punkt/.style={ rectangle, rounded corners, draw=black, very thick, text width=6.5em, minimum height=2em, text centered}, % Define arrow style pil/.style={ ->, semithick, shorten <= 0pt, shorten >= 0pt,}, pild/.style={ ->, thick, %>=angle 90, shorten <= 0pt, shorten >= 0pt,} } \pgfkeys{ /tikz/external/mode=list and make } \pgfplotsset{ xtick scale label code/.code={$\times 10^{#1}$} } \pgfplotsset{ ytick scale label code/.code={$\times 10^{#1}$} } \pgfplotsset{ invoke before crossref tikzpicture={\tikzexternaldisable}, invoke after crossref tikzpicture={\tikzexternalenable}, } % for listing \usepackage{listings} \lstset{ basicstyle=\scriptsize\ttfamily, tabsize=3, showtabs=false, showspaces=false, showstringspaces=false, tab=\rightarrowfill, frame=none, numbers=left, numberstyle=\tiny, numbersep=5pt, captionpos=top, frame=tb, firstnumber=1, stepnumber=1, % numberfirstline=false, breaklines=true, breakatwhitespace=true, % prebreak=\mbox{\,$\color{ListingsBreakSymbolColor}\mathbf{\hookleftarrow}$}, mathescape=true, morekeywords={}, } \usepackage{url} \usepackage[final]{hyperref} \hypersetup{ % Farben fuer die Links colorlinks=false, % Links erhalten Farben statt Kaeten % Links raiselinks=true, % calculate real height of the link breaklinks, % Links berstehen Zeilenumbruch %backref=page, % Backlinks im Literaturverzeichnis (section, slide, page, none) %pagebackref=true, % Backlinks im Literaturverzeichnis mit Seitenangabe verbose, % hyperindex=true, % backlinkex index linktocpage=true, % Inhaltsverzeichnis verlinkt Seiten % hyperfootnotes=false, % Keine Links auf Fussnoten % Bookmarks % bookmarks=true, % Erzeugung von Bookmarks fuer PDF-Viewer bookmarksopenlevel=1, % Gliederungstiefe der Bookmarks bookmarksopen=false, % Expandierte Untermenues in Bookmarks bookmarksnumbered=true, % Nummerierung der Bookmarks bookmarkstype=toc, % Art der Verzeichnisses % Anchors plainpages=false, % Anchors even on plain pages ? pageanchor=true, % Pages are linkable % PDF Informationen pdftitle={\reporttitle: \reportsubtitle. \reportsubsubtitle}, % Titel pdfauthor={Roman Iakymchuk}, % Autor pdfcreator={LaTeX, hyperref, KOMA-Script}, pdfstartview=Fit, % Dokument wird Fit Height geaefnet pdffitwindow=true, pdfpagemode=UseOutlines, % Bookmarks im Viewer anzeigen % pdfpagelabels=true, % set PDF page labels } \usepackage{cleveref} \Crefname{figure}{Fig.}{Figs.} % to disable some warnings \usepackage{silence} \WarningFilter{latex}{Citation} \WarningFilter{latex}{Reference} \WarningFilter{latex}{Text page 8 contains only floats} \WarningFilter{rerunfilecheck}{File} \WarningFilter{latex}{There were undefined references} \WarningFilter{latex}{Label(s) may have changed} \newcommand{\bytes}{b} \newcommand{\kb}{Kb} \newcommand{\mb}{Mb} \newcommand{\ghz}{GHz} \newcommand{\flop}{Flop} \newcommand{\flops}{Flops} \newcommand{\gflops}{G\flops} \newcommand{\eztrace}{EZTrace} \newcommand{\fxt}{FxT} \newcommand{\pthread}{Pthreads} \newcommand{\openmp}{OpenMP} \newcommand{\mpi}{MPI} \newcommand{\dash}{ -- } \date{} LiTL-litl-0.2/doc/references.bib000066400000000000000000000013421415666016500164770ustar00rootroot00000000000000 @inproceedings{litl, author = {Roman Iakymchuk and Fran\c{c}ois Trahay}, title = {\litl{}: Lightweight Trace Library}, booktitle = {Proceedings of the 25th International Symposium on Computer Architecture and High Performance Computing (SBAC-PAD'2013), Porto de Galinhas, Pernambuco, Brazil, October 23-26}, series = {}, year = {2013}, pages = {} } @inproceedings{Danjean05FxT, author = {Danjean, Vincent and Namyst, Raymond and Wacrenier, Pierre-Andr{\'e}}, title = {An efficient multi-level trace toolkit for multi-threaded applications}, booktitle = {Proceedings of the 11th international Euro-Par conference on Parallel Processing}, series = {Euro-Par'05}, year = {2005}, pages = {166--175} } LiTL-litl-0.2/doc/tikz/000077500000000000000000000000001415666016500146615ustar00rootroot00000000000000LiTL-litl-0.2/doc/tikz/event.recording.all.tex000066400000000000000000000106721415666016500212540ustar00rootroot00000000000000 \begin{figure}[!t] \begin{center} \begin{footnotesize} \subfigure[\fxt{}]{ \label{fig:event_recording_fxt} \begin{tikzpicture}[scale=.88] % threads \node at (98.5, 100.3) {Process}; \node[rotate=-90] at (100.3, 99.4) {Threads}; \draw [blue, line width=.3mm, rounded corners] (100.,100.) rectangle (97.,98.8); \foreach \x in {99.7,99.1,...,97.} \draw [line width=.24mm, decorate,decoration={snake,post length=1mm}] (\x,99.9) -- (\x,98.9); % buffer \draw [blue, fill=blue, line width=.3mm, rounded corners] (100.5,98.) rectangle (96.5,96.4); \node at (98.5, 97.2) {B U F F E R}; % 0 \node at (98.2, 98.) (buffer0up) {}; \node at (97.23, 98.96) (thread0) {} edge[pil] (buffer0up.north); % 1 \node at (98.35, 98.) (buffer1up) {}; \node at (97.84, 98.96) (thread1) {} edge[pil] (buffer1up.north); % 2 \node at (98.5, 98.) (buffer2up) {}; \node at (98.5, 98.96) (thread2) {} edge[pil] (buffer2up.north); % 3 \node at (98.65, 98.) (buffer3up) {}; \node at (99.13, 98.96) (thread3) {} edge[pil] (buffer3up.north); % 4 \node at (98.8, 98.) (buffer4up) {}; \node at (99.76, 98.96) (thread4) {} edge[pil] (buffer4up.north); % trace file \draw [blue, fill=gray, line width=.3mm, rounded corners] (99.8,95.6) rectangle (97.2,94.5); \node at (98.5, 95.6) (trace) {}; \node at (98.5, 96.4) (bufferdown) {} edge[pild] (trace.north); \draw [blue, fill=white, line width=.3mm, rounded corners] (99.8,95.3) rectangle (97.2,94.5); \node at (98.5, 94.9) {Trace File}; \end{tikzpicture} }\hspace*{8mm} \subfigure[\litl]{ \label{fig:event_recording_litl} \begin{tikzpicture}[scale=.88] % threads \node at (98.5, 100.3) {Process}; \node[rotate=-90] at (100.3, 99.4) {Threads}; \draw [blue, line width=.3mm, rounded corners] (100.,100.) rectangle (97.,98.8); \foreach \x in {99.7,99.1,...,97.} \draw [line width=.24mm, decorate,decoration={snake,post length=1mm}] (\x,99.9) -- (\x,98.9); % buffers % 0 \draw [blue, fill=blue, line width=.3mm, rounded corners] (101.,98.) rectangle (100.3,96.4); \node at (100.55, 98.) (buffer0up) {}; \node at (99.66, 98.96) (thread0) {} edge[pil] (buffer0up.north); % 1 \draw [blue, fill=blue, line width=.3mm, rounded corners] (100.,98.) rectangle (99.3,96.4); \node at (99.6, 98.) (buffer1up) {}; \node at (99.06, 98.96) (thread1) {} edge[pil] (buffer1up.north); % dots \node at (98.9,97.2) {$\dots$}; % 2 \draw [blue, fill=blue, line width=.3mm, rounded corners] (98.5,98.) rectangle (97.8,96.4); \node at (98.13, 98.) (buffer2up) {}; \node at (98.53, 98.96) (thread2) {} edge[pil] (buffer2up.north); % 3 \draw [blue, fill=blue, line width=.3mm, rounded corners] (97.5,98.) rectangle (96.8,96.4); \node at (97.15, 98.) (buffer3up) {}; \node at (97.95, 98.96) (thread3) {} edge[pil] (buffer3up.north); % 4 \draw [blue, fill=blue, line width=.3mm, rounded corners] (96.5,98.) rectangle (95.8,96.4); \node at (96.15, 98.) (buffer4up) {}; \node at (97.33, 98.95) (thread4) {} edge[pil] (buffer4up.north); \node[rotate=-90] at (101.35, 97.2) {BUFFERS}; % trace file \draw [blue, fill=gray, line width=.3mm, rounded corners] (99.8,95.6) rectangle (97.2,94.5); \draw [blue, fill=white, line width=.3mm, rounded corners] (99.8,95.3) rectangle (97.2,94.5); \node at (98.5, 94.9) {Trace File}; % arrows \node at (98.75, 95.6) (trace0) {}; \node at (100.65, 96.4) (buffer0down) {} edge[pil] (trace0.north); \node at (98.55, 95.6) (trace1) {}; \node at (99.7, 96.4) (buffer1down) {} edge[pil] (trace1.north); \node at (98.5, 95.6) (trace2) {}; \node at (98.13, 96.4) (buffer2down) {} edge[pil] (trace2.north); \node at (98.4, 95.6) (trace3) {}; \node at (97.1, 96.4) (buffer3down) {} edge[pil] (trace3.north); \node at (98.2, 95.6) (trace4) {}; \node at (96.1, 96.4) (buffer4down) {} edge[pil] (trace4.north); \end{tikzpicture} } \end{footnotesize} \caption{Event recording mechanism on multi-threaded applications.} \label{fig:event_recording_all} \end{center} \end{figure} LiTL-litl-0.2/doc/tikz/event.storage.all.line.packed.tex000066400000000000000000000155711415666016500231230ustar00rootroot00000000000000 \begin{figure}[!t] \begin{center} \begin{footnotesize} \subfigure[Regular Events]{ \label{fig:event_storage_fxt} \begin{tikzpicture}[scale=.88] % vertical lines \foreach \x in {.125,.25,...,21.875} \draw[blue,line width=.12mm](\x,1.2) -- (\x,1.6);gray % event5 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (0.02,2.1) -- (8.98, 2.1) node[midway]{event5}; \draw (0.5, 1.4) -- (0.5, 1.4) node{time}; \draw[gray,line width=.2mm](1.,1.2) -- (1.,1.6); \draw (1.5, 1.4) -- (1.5, 1.4) node{tid}; \draw[gray,line width=.2mm](2.,1.2) -- (2.,1.6); \draw (2.25, 1.35) -- (2.25, 1.35) node{cpu}; \draw[gray,line width=.2mm](2.5,1.2) -- (2.5,1.6); \draw (3., 1.4) -- (3., 1.4) node{code}; \draw[gray,line width=.2mm](3.5,1.2) -- (3.5,1.6); \draw (3.75, 1.35) -- (3.75, 1.35) node{np}; \draw[gray,line width=.2mm](4.,1.2) -- (4.,1.6); \draw (4.5, 1.4) -- (4.5, 1.4) node{par0}; \draw[gray,line width=.2mm](5.,1.2) -- (5.,1.6); \draw (5.5, 1.4) -- (5.5, 1.4) node{par1}; \draw[gray,line width=.2mm](6.,1.2) -- (6.,1.6); \draw (6.5, 1.4) -- (6.5, 1.4) node{par2}; \draw[gray,line width=.2mm](7.,1.2) -- (7.,1.6); \draw (7.5, 1.4) -- (7.5, 1.4) node{par3}; \draw[gray,line width=.2mm](8.,1.2) -- (8.,1.6); \draw (8.5, 1.4) -- (8.5, 1.4) node{par4}; \draw[gray,line width=.4mm](9.,1.2) -- (9.,1.6); % event2 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (9.02,2.1) -- (14.98, 2.1) node[midway]{event2}; \draw (9.5, 1.4) -- (9.5, 1.4) node{time}; \draw[gray,line width=.2mm](10.,1.2) -- (10.,1.6); \draw (10.5, 1.4) -- (10.5, 1.4) node{tid}; \draw[gray,line width=.2mm](11.,1.2) -- (11.,1.6); \draw (11.25, 1.35) -- (11.25, 1.35) node{cpu}; \draw[gray,line width=.2mm](11.5,1.2) -- (11.5,1.6); \draw (12., 1.4) -- (12., 1.4) node{code}; \draw[gray,line width=.2mm](12.5,1.2) -- (12.5,1.6); \draw (12.75, 1.35) -- (12.75, 1.35) node{np}; \draw[gray,line width=.2mm](13.,1.2) -- (13.,1.6); \draw (13.5, 1.4) -- (13.5, 1.4) node{par0}; \draw[gray,line width=.2mm](14.,1.2) -- (14.,1.6); \draw (14.5, 1.4) -- (14.5, 1.4) node{par1}; \draw[gray,line width=.4mm](15.,1.2) -- (15.,1.6); % event3 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (15.02,2.1) -- (21.98, 2.1) node[midway]{event3}; \draw (15.5, 1.4) -- (15.5, 1.4) node{time}; \draw[gray,line width=.2mm](16.,1.2) -- (16.,1.6); \draw (16.5, 1.4) -- (16.5, 1.4) node{tid}; \draw[gray,line width=.2mm](17.,1.2) -- (17.,1.6); \draw (17.25, 1.35) -- (17.25, 1.35) node{cpu}; \draw[gray,line width=.2mm](17.5,1.2) -- (17.5,1.6); \draw (18., 1.4) -- (18., 1.4) node{code}; \draw[gray,line width=.2mm](18.5,1.2) -- (18.5,1.6); \draw (18.75, 1.35) -- (18.75, 1.35) node{np}; \draw[gray,line width=.2mm](19.,1.2) -- (19.,1.6); \draw (19.5, 1.4) -- (19.5, 1.4) node{par0}; \draw[gray,line width=.2mm](20.,1.2) -- (20.,1.6); \draw (20.5, 1.4) -- (20.5, 1.4) node{par1}; \draw[gray,line width=.2mm](21.,1.2) -- (21.,1.6); \draw (21.5, 1.4) -- (21.5, 1.4) node{par2}; % big rectangle \draw [blue, line width=.3mm] (0.,1.2) rectangle (22.,1.6); \end{tikzpicture} } \subfigure[Packed Events]{ \label{fig:event_storage_litl} \hspace*{2mm}\begin{tikzpicture}[scale=.88] % vertical lines \foreach \x in {.125,.25,...,21.875} \draw[blue,line width=.12mm](\x,1.2) -- (\x,1.6);gray % event5 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (0.02,2.1) -- (3.105, 2.1) node[midway]{event5}; \draw (0.5, 1.4) -- (0.5, 1.4) node{time}; \draw[gray,line width=.2mm](1.,1.2) -- (1.,1.6); \draw (1.25, 1.4) -- (1.25, 1.4) node{cd}; \draw[gray,line width=.2mm](1.5,1.2) -- (1.5,1.6); \draw (1.75, 1.36) -- (1.75, 1.36) node{tp}; \draw[gray,line width=.2mm](2.,1.2) -- (2.,1.6); \draw (2.25, 1.35) -- (2.25, 1.35) node{np}; \draw[gray,line width=.2mm](2.5,1.2) -- (2.5,1.6); \draw (2.8, 1.35) -- (2.8, 1.35) node{par}; \draw[gray,line width=.4mm](3.125,1.2) -- (3.125,1.6); % event2 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (3.145,2.1) -- (5.855, 2.1) node[midway]{event2}; \draw (3.625, 1.4) -- (3.625, 1.4) node{time}; \draw[gray,line width=.2mm](4.125,1.2) -- (4.125,1.6); \draw (4.375, 1.4) -- (4.375, 1.4) node{cd}; \draw[gray,line width=.2mm](4.625,1.2) -- (4.625,1.6); \draw (4.875, 1.36) -- (4.875, 1.36) node{tp}; \draw[gray,line width=.2mm](5.125,1.2) -- (5.125,1.6); \draw (5.375, 1.35) -- (5.375, 1.35) node{np}; \draw[gray,line width=.2mm](5.625,1.2) -- (5.625,1.6); \draw [ semithick, decorate, decoration={ brace, amplitude=2.5pt, raise=-0.065cm }] (5.5,1.13) -- (5.99, 1.13) node[midway,below]{par}; \draw[gray,line width=.4mm](5.875,1.2) -- (5.875,1.6); % event3 \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (5.895,2.1) -- (8.73, 2.1) node[midway]{event3}; \draw (6.375, 1.4) -- (6.375, 1.4) node{time}; \draw[gray,line width=.2mm](6.875,1.2) -- (6.875,1.6); \draw (7.125, 1.4) -- (7.125, 1.4) node{cd}; \draw[gray,line width=.2mm](7.375,1.2) -- (7.375,1.6); \draw (7.625, 1.36) -- (7.625, 1.36) node{tp}; \draw[gray,line width=.2mm](7.875,1.2) -- (7.875,1.6); \draw (8.125, 1.35) -- (8.125, 1.35) node{np}; \draw[gray,line width=.2mm](8.375,1.2) -- (8.375,1.6); \draw [ semithick, decorate, decoration={ brace, amplitude=2.5pt, raise=-0.065cm }] (8.305,1.13) -- (8.8, 1.13) node[midway,below]{par}; \draw[gray,line width=.4mm](8.75,1.2) -- (8.75,1.6); % saved space \draw [ semithick, decorate, decoration={ brace, amplitude=5pt, raise=-0.35cm }] (8.77,2.1) -- (21.98, 2.1) node[midway]{saved space}; % gray rectangle \draw [gray, fill=blue, line width=.12mm] (8.77,1.2) rectangle (22.,1.6); % big rectangle \draw [blue, line width=.3mm] (0.,1.2) rectangle (22.,1.6); \end{tikzpicture} } \end{footnotesize} \caption{Storage of different kinds of events in the trace file. In the figure, \emph{time} is the time when the event occurred; \emph{cd} means the event code; \emph{tp} is the event type; \emph{np} stands for the number of event's parameters; \emph{par}\dash{}an array of parameters.} \label{fig:event_storage_all} \end{center} \end{figure} LiTL-litl-0.2/doc/tikz/event.storage.trace.file.merge.tex000066400000000000000000000075661415666016500233160ustar00rootroot00000000000000 \begin{figure*}[!t] \begin{center} \begin{footnotesize} \hspace*{-1mm} \begin{tikzpicture}[scale=1.2] \draw [blue, fill=blue, line width=.35mm, rounded corners] (0.,0.) rectangle (18.5,1.); % header \draw [green, fill=white, line width=.3mm, rounded corners] (0.1,0.1) rectangle (7.71,.9); \draw [green, line width=.3mm] (.1, .6) -- (7.71, .6); \node at (3.7, .73) {H E A D E R}; % #trace files \draw [gray, fill=white, line width=.3mm, rounded corners] (.15,0.15) rectangle (1.15,.55); \node at (.65, .35) {\#traces}; % fids and offsets \draw [gray, fill=white, line width=.3mm, rounded corners] (1.2,0.15) rectangle (3.32,.55); \node at (1.5, .35) {fid0}; \draw [gray, line width=.3mm] (1.76, .15) -- (1.76, .55); \node at (2.1, .35) {size0}; \draw [gray, line width=.3mm] (2.43, .15) -- (2.43, .55); \node at (2.86, .35) {offset0}; \draw [gray, fill=white, line width=.3mm, rounded corners] (3.37,0.15) rectangle (5.49,.55); \node at (3.66, .35) {fid1}; \draw [gray, line width=.3mm] (3.91, .15) -- (3.91, .55); \node at (4.27, .35) {size1}; \draw [gray, line width=.3mm] (4.59, .15) -- (4.59, .55); \node at (5.04, .35) {offset1}; \draw [gray, fill=white, line width=.3mm, rounded corners] (5.54,0.15) rectangle (7.66,.55); \node at (5.83, .35) {fid2}; \draw [gray, line width=.3mm] (6.09, .15) -- (6.09, .55); \node at (6.43, .35) {size2}; \draw [gray, line width=.3mm] (6.76, .15) -- (6.76, .55); \node at (7.2, .35) {offset2}; % trace0 \draw [green, fill=white, line width=.3mm, rounded corners] (7.81,0.1) rectangle (11.27,.9); \draw [green, line width=.3mm] (7.81, .6) -- (11.27, .6); \node at (9.51, .73) {Trace0}; \node at (7.94,.9) (trace0) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (7.86,0.15) rectangle (9.56,.55); \node at (8.71, .37) {\textsc{header0}}; \draw [gray, fill=white, line width=.3mm, rounded corners] (9.61,0.15) rectangle (11.22,.55); \node at (10.42, .35) {\textsc{events}}; % trace1 \draw [green, fill=white, line width=.3mm, rounded corners] (11.37,0.1) rectangle (14.83,.9); \draw [green, line width=.3mm] (11.37, .6) -- (14.83, .6); \node at (13.07, .73) {Trace1}; \node at (11.5,.9) (trace1) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (11.42,0.15) rectangle (13.07,.55); \node at (12.25, .37) {\textsc{header1}}; \draw [gray, fill=white, line width=.3mm, rounded corners] (13.12,0.15) rectangle (14.77,.55); \node at (13.95, .35) {\textsc{events}}; % trace2 \draw [green, fill=white, line width=.3mm, rounded corners] (14.93,0.1) rectangle (18.39,.9); \draw [green, line width=.3mm] (14.93, .6) -- (18.39, .6); \node at (16.63, .73) {Trace2}; \node at (15.06,.9) (trace2) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (14.98,0.15) rectangle (16.67,.55); \node at (15.82, .37) {\textsc{header2}}; \draw [gray, fill=white, line width=.3mm, rounded corners] (16.72,0.15) rectangle (18.34,.55); \node at (17.53, .35) {\textsc{events}}; % arrows \node at (2.74, .45) (offset0) {} edge[pil, densely dotted, bend right=-40] (trace0.west); \node at (4.92, .45) (offset1) {} edge[pil, bend right=-40] (trace1.west); \node at (7.08, .45) (offset2) {} edge[pil, dashed, bend right=-40] (trace2.west); \end{tikzpicture} \end{footnotesize} \caption{The structure of an archive composed of multiple trace files. In the figure, \emph{fid} stands for the trace file name; \emph{size} is the size of a merged trace file.} \label{fig:storage_trace_merge} \end{center} \end{figure*} LiTL-litl-0.2/doc/tikz/event.storage.trace.file.tex000066400000000000000000000133641415666016500222110ustar00rootroot00000000000000 \begin{figure*}[!t] \begin{center} \begin{footnotesize} \hspace*{-1mm} \begin{tikzpicture}[scale=1.2] \draw [blue, fill=blue, line width=.35mm, rounded corners] (0.,0.) rectangle (18.5,1.); % header \draw [green, fill=white, line width=.3mm, rounded corners] (0.1,0.1) rectangle (8.4,.9); \draw [green, line width=.3mm] (.1, .6) -- (8.4, .6); \draw (4.2, .73) -- (4.2, .73) node{H E A D E R}; % litl version and OS \draw [gray, fill=white, line width=.3mm, rounded corners] (.15,0.15) rectangle (1.15,.55); %\draw (.65, .35) -- (.65, .35) node{\litl{\_}v}; \node at (.65, .35) {\litl{\_}v}; \draw [gray, fill=white, line width=.3mm, rounded corners] (1.2,0.15) rectangle (1.6,.55); \draw (1.4, .35) -- (1.4, .35) node{OS}; % buffer size and #threads \draw [gray, fill=white, line width=.3mm, rounded corners] (1.65,0.15) rectangle (2.75,.55); \draw (2.2, .35) -- (2.2, .35) node{\#threads}; \draw [gray, fill=white, line width=.3mm, rounded corners] (2.8,0.15) rectangle (3.85,.55); \draw (3.33, .35) -- (3.33, .35) node{buf\_size}; % tids and offsets \draw [gray, fill=white, line width=.3mm, rounded corners] (3.9,0.15) rectangle (5.35,.55); \draw (4.2, .35) -- (4.2, .35) node{tid0}; \draw [gray, line width=.3mm] (4.46, .15) -- (4.46, .55); \node at (4.93, .35) {offset0}; \draw [gray, fill=white, line width=.3mm, rounded corners] (5.4,0.15) rectangle (6.85,.55); \draw (5.7, .35) -- (5.7, .35) node{tid1}; \draw [gray, line width=.3mm] (5.96, .15) -- (5.96, .55); \draw (6.43, .35) -- (6.43, .35) node{offset1}; \draw [gray, fill=white, line width=.3mm, rounded corners] (6.9,0.15) rectangle (8.35,.55); \draw (7.2, .35) -- (7.2, .35) node{tid2}; \draw [gray, line width=.3mm] (7.46, .15) -- (7.46, .55); \draw (7.93, .35) -- (7.93, .35) node{offset2}; % chunk00 \draw [green, fill=white, line width=.3mm, rounded corners] (8.5,0.1) rectangle (10.4,.9); \draw [green, line width=.3mm] (8.5, .6) -- (10.4, .6); \node at (8.65,0.9) (chunk00) {}; \draw (9.45, .73) -- (9.45, .73) node{chunk00}; \draw [gray, fill=white, line width=.3mm, rounded corners] (8.55,0.15) rectangle (9.35,.55); \draw (8.95, .35) -- (8.95, .35) node{events}; \draw [gray, fill=white, line width=.3mm, rounded corners] (9.4,0.15) rectangle (10.35,.55); \draw (9.88, .35) -- (9.88, .35) node{offset01}; % chunk20 \draw [green, fill=white, line width=.3mm, rounded corners] (10.5,0.1) rectangle (12.4,.9); \draw [green, line width=.3mm] (10.5, .6) -- (12.4, .6); \draw (11.45, .73) -- (11.45, .73) node{chunk20}; \node at (10.65,0.9) (chunk20) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (10.55,0.15) rectangle (11.35,.55); \draw (10.95, .35) -- (10.95, .35) node{events}; \draw [gray, fill=white, line width=.3mm, rounded corners] (11.4,0.15) rectangle (12.35,.55); \draw (11.88, .35) -- (11.88, .35) node{offset21}; % chunk01 \draw [green, fill=white, line width=.3mm, rounded corners] (12.5,0.1) rectangle (14.4,.9); \draw [green, line width=.3mm] (12.5, .6) -- (14.4, .6); \draw (13.45, .73) -- (13.45, .73) node{chunk01}; \node at (12.65,0.9) (chunk01) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (12.55,0.15) rectangle (13.35,.55); \draw (12.95, .35) -- (12.95, .35) node{events}; \draw [gray, fill=white, line width=.3mm, rounded corners] (13.4,0.15) rectangle (14.35,.55); \draw (13.88, .35) -- (13.88, .35) node{offset02}; % chunk10 \draw [green, fill=white, line width=.3mm, rounded corners] (14.5,0.1) rectangle (16.4,.9); \draw [green, line width=.3mm] (14.5, .6) -- (16.4, .6); \draw (15.45, .73) -- (15.45, .73) node{chunk10}; \node at (14.65,0.9) (chunk10) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (14.55,0.15) rectangle (15.35,.55); \draw (14.95, .35) -- (14.95, .35) node{events}; \draw [gray, fill=white, line width=.3mm, rounded corners] (15.4,0.15) rectangle (16.35,.55); \draw (15.88, .35) -- (15.88, .35) node{offset11}; % chunk02 \draw [green, fill=white, line width=.3mm, rounded corners] (16.5,0.1) rectangle (18.4,.9); \draw [green, line width=.3mm] (16.5, .6) -- (18.4, .6); \draw (17.45, .73) -- (17.45, .73) node{chunk02}; \node at (16.65,0.9) (chunk02) {}; \draw [gray, fill=white, line width=.3mm, rounded corners] (16.55,0.15) rectangle (17.35,.55); \draw (16.95, .35) -- (16.95, .35) node{events}; \draw [gray, fill=white, line width=.3mm, rounded corners] (17.4,0.15) rectangle (18.35,.55); \draw (17.88, .35) -- (17.88, .35) node{offset03}; % arrows \node at (4.8, .45) (offset0) {} edge[pil, bend right=-40] (chunk00.west); \node at (6.3, .45) (offset1) {} edge[pil, dashed, bend right=-40] (chunk10.west); \node at (7.8, .45) (offset2) {} edge[pil, densely dotted, bend right=-40] (chunk20.west); \node at (9.75, .45) (offset01) {} edge[pil, bend right=-40] (chunk01.west); \node at (13.75, .45) (offset02) {} edge[pil, bend right=-40] (chunk02.west); \end{tikzpicture} \end{footnotesize} \caption{Storage of events recorded by \litl{} on multi-threaded applications. In the figure, \emph{\litl{\_}v} contains information about \litl{}; \emph{OS}\dash{}about OS and architecture; \emph{\#threads} stands for the number of threads; \emph{buf\_size}\dash{}the buffer size.} \label{fig:event_storage_trace} \end{center} \end{figure*} LiTL-litl-0.2/doc/user_manual.tex.in000066400000000000000000000542461415666016500173550ustar00rootroot00000000000000\include{header} % Title Page \title{ {\Huge\bf \reporttitle{}}\\[6mm] {\LARGE\bf \reportsubtitle}\\[12mm] {\Large\bf \reportsubsubtitle}} \author{Roman Iakymchuk and Fran\c{c}ois Trahay} \begin{document} \hypersetup{pageanchor=false} \maketitle \hypersetup{pageanchor=true} % \setcounter{page}{2} \tableofcontents \chapter{License of \litl} Copyright (c) 2013, Télécom SudParis\\ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \begin{itemize} \item Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \item 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. \end{itemize} 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. \chapter{Overview of \litl} \litl{}~\cite{litl} is a lightweight binary trace library that aims at providing performance analysis tools with a scalable event recording mechanism that utilizes minimum resources of the CPU and memory. In order to efficiently analyze modern HPC applications that combine \openmp{} (or \pthread) threads and \mpi{} processes, we design and implement various mechanisms to ensure the scalability of \litl{} for a large number of both threads and processes. \litl{} is designed in order to resolve the following performance tracing issues: \begin{itemize} \item Scalability and the number of threads; \item Scalability and the number of recorded traces; \item Optimization in the storage capacity usage. \end{itemize} As a result, \litl{} provides similar functionality to standard event recording libraries and records events only from user-space. \litl{} minimizes the usage of the CPU time and memory space in order to avoid disturbing the application that is being analyzed. Also, \litl{} is fully thread-safe that allows to record events from multi-threaded applications. Finally, \litl{} is a generic library that can be used in conjunction with many performance analysis tools and frameworks. \chapter{Installation} \section{Requirements} In order to use \litl{}, the following software is required: \begin{enumerate} \item autoconf of version 2.63; \end{enumerate} \section{Getting \litl} Current development version of \litl{} is available via Git\\ \hspace*{0.9cm}\texttt{git clone git+ssh://fusionforge.int-evry.fr//var/lib/}\\ \hspace*{0.9cm}\texttt{gforge/chroot/scmrepos/git/litl/litl.git}\\ After getting the latest development version from Git, the following command should be run\\ \hspace*{0.9cm}\texttt{./bootstrap}\\ And, only afterwards the tool can be built. \section{Building \eztrace{}} At first, to configure \litl{} the following configure script should be invoked\\ \hspace*{0.9cm}\texttt{./configure -\,-prefix=}\\ The configuration script contains many different options that can be set. However, during the first try we recommend to use the default settings. Once \litl{} is configured, the next two commands should be executed to complete the building\\ \hspace*{0.9cm}\texttt{make}\\ \hspace*{0.9cm}\texttt{make install} In order to check whether \litl{} was installed correctly, a set of tests can be run as\\ \hspace*{0.9cm}\texttt{make check} \chapter{How to Use \litl{}?} \section{Reading Events} After the application was traced and events were recorded into binary trace files, those traces can be analyzed using \texttt{litl\_read} as\\ \hspace*{0.9cm}\texttt{litl\_read -f trace.file}\\ This utility shows the recorded events in the following format: \begin{itemize} \item Time since last probe record on the same CPU; \item ID of the current thread on this CPU; \item Event type; \item Code of the probe; \item Number of parameters of the probe; \item List of parameters of the probe, if any. \end{itemize} \section{Merging Traces} Once the traces were recorded, they can be merged into an archive of traces for further processing by the following command\\ \hspace*{0.9cm}\texttt{litl\_read -o archive.trace trace.0 trace.1 ... trace.n} \section{Splitting Traces} In case of a need for a detailed analysis of a particular trace files, an archive of traces can be split back into separate traces by\\ \hspace*{0.9cm}\texttt{litl\_read -f archive.trace -d output.dir} \section{Environment Variables} For a more flexible and comfortable usage of \litl{}, we provide the following environment variables: \begin{itemize} \item \texttt{LITL\_BUFFER\_SIZE} provides users with the alternative possibility to set a buffer size. If the variable is not specified, then the provided value inside the application is used; \item \texttt{LITL\_BUFFER\_FLUSH} specifies the behavior of \litl{} when the event buffer is full. If it is set to ``0'', \litl{} stop recording events. The trace is, thus, truncated and there is no impact on the application performance. If it is set to ``1'' the buffer is written to disk and additional events can be recorded. This permits to record traces that are larger than the buffer size. Please note that the Flush policy may have a significant impact on the application performance since it requires to write a large amount of data to disk during the execution of the application. The default value is \textbf{0}. \item \texttt{LITL\_TID\_RECORDING} provides users with an alternative possibility to enable or disable tid recording. If it is set to ``1'', the tid recording is enabled. Otherwise, when it is set to ``0'', the tid recording is disable; The default value is \textbf{1}. \item \texttt{LITL\_THREAD\_SAFETY} specifies the behavior of \litl{} while tracing multi-threaded applications. If it is set to ``1'', the thread safety is enabled. Otherwise, when it is set to ``0'', the event recording is not thread safe; The default value is \textbf{1}. \item \texttt{LITL\_TIMING\_METHOD} specifies the timing method that will be used during the recording phase. The \litl{} timing methods can be divided into two groups: those that measure time in clock ticks and those that rely on the \texttt{clock\_gettime()} function. The first group has only one method: \begin{itemize} \item \texttt{ticks} that uses the CPU specific register, e.g. rdtsc on X86 and X86\_64 architectures. \end{itemize} The second group comprises of the other five different methods: \begin{itemize} \item \texttt{monotonic} that corresponds to \texttt{CLOCK\_MONOTONIC}; \item \texttt{monotonic\_raw}\dash{}\texttt{CLOCK\_MONOTONIC\_RAW}; \item \texttt{realtime}\dash{}\texttt{CLOCK\_REALTIME}; \item \texttt{thread\_cputime}\dash{}\texttt{CLOCK\_THREAD\_CPUTIME\_ID}; \item \texttt{process\_cputime}\dash{}\texttt{CLOCK\_PROCESS\_CPUTIME\_ID}. \end{itemize} User can also define its own timing method and set the environment variable accordingly. \end{itemize} \chapter{\litl{} in Details} \section{Event Types and The Storage Usage} Each event in the \litl{} library consists of two parts: the event core (the event code, the time when the event occurred, the thread identifier, and the number of parameters) and event parameters. The number of event parameters recorded by \litl{} varies from zero to ten. The parameters passed to each event have different data type. In order to handle the variety of possible cases, event's parameters in \litl{} can be represented by the largest data type, which is \texttt{uint64\_t} on x86\_64 architectures. Hence, any parameter -- no matter whether it is a \texttt{char}, an \texttt{int} or a \texttt{long int} -- can be recorded without being truncated. However, the reserved slot for each parameter is often bigger than its actual size. Thus, this leads to the non-optimal usage of resources. Our goal is to keep trace files as small as possible without losing any of the recorded data. Therefore, we propose to use the compacted event storage that aims at utilizing every byte from the allocated space. In our approach, we introduce three different types of events: regular, raw, and packed. The regular event is without any major optimization being involved. The raw event stores parameters in the string format. Its purpose is to gather either the regular parameters in a string format or the information about the abnormal behavior of applications like thrown exceptions. The packed event represents the optimized versions of storing events, where each parameter can be saved as a group of bytes. Accordingly, by using the event type packed for recording and storing events, we theoretically are capable to save up to 65\,\% of the disk space compare to the regular \litl{}. \Cref{fig:event_storage_fxt} shows, on an example of three regular events with different number of parameters, the occupied space of events within the trace file recorded by \eztrace\ with \litl{}. We symbolically partitioned the trace file into bytes and also chunks of bytes, which store event's components. The space occupied by each event is highlighted with parentheses. \begin{landscape} \input{@top_srcdir@/doc/tikz/event.storage.all.line.packed} \input{@top_srcdir@/doc/tikz/event.storage.trace.file} \end{landscape} \Cref{fig:event_storage_litl} shows the storage of the recorded packed events in the trace file while using \eztrace\ with \litl{}. We consider one particular scenario when each event's parameter can be represented by \texttt{uint8\_t}; this requires only one byte for the storage. To store larger event's parameters we use arrays of \texttt{uint8\_t}. This scenario corresponds to the optimal performance in terms of the memory and disk space usage. Under this approach, not only the size of the core event's components is shrunk, but also the size of event's parameters is reduced significantly. The gained performance, e.i. the reduced space, can be characterized by the gray area that corresponds to the difference in storage between the regular and packed events. The size of three packed events is smaller than the size of one regular event with five parameters. This figure confirms our assumption regarding the possibility of reducing the size of both the recorded events and trace files. \section{Scalability vs. the Number of Threads} The advent of multi-core processor have led to the increase in the number of processing units per machine. It becomes usual to equip a typical high performance computing platform with 8, 16, or even more cores per node. In order to exploit efficiently such facilities, developers can use hybrid programming models that mix \openmp{} (or \pthread) threads and \mpi{} processes within one application. Hence, the number of threads per node, which executes the same application, can be quite large\dash{}8, 16, or even more threads. The number of threads per node is the scalability issue for the conventional binary tracing libraries such as \fxt{}~\cite{Danjean05FxT}, because in its implementation all threads within one process record events into a single buffer, see~\Cref{fig:event_recording_fxt}. This recording mechanism causes a {\em contention} problem\dash{}when multiple threads record events simultaneously, the pointer to the next available slot in the buffer is changed concurrently. The modifications of the pointer can be done atomically in order to preserve the data consistency. However, the atomic operation does not scale quite well when it is performed by a large number of threads at the same time. Thus, analyzing \openmp{} applications that run lots of threads using such tracing libraries may result in the high overhead. \input{@top_srcdir@/doc/tikz/event.recording.all} \subsection{Recording Events} While designing \litl{}, we aim at resolving the above-mentioned limitation of \fxt{}. Thus, we propose to record events into separate buffers, meaning to have one buffer per thread instead of one buffer per process. This approach is illustrated on~\Cref{fig:event_recording_litl}. To keep multiple buffers in order within the trace file, we add a header into the trace file with the information regarding the number of threads and pairs \emph{}; \emph{tid} stands for the thread identifier; \emph{offset} corresponds to the position of the first chunk of events for a given thread within the trace starting from its beginning. The last event of each chunk contains either an \emph{offset} to the next chunk of events or a symbol specifying the end of recording for a given thread. While flushing the current buffer to the trace file, the following two actions are performed: \begin{enumerate} \item Setting the offset of the current chunk to specify the end of the recording; \item Update the offset from the previous chunk to point to the current one. \end{enumerate} \Cref{fig:event_storage_trace} demonstrates the storage mechanism on an example of three threads, including the positioning of chunks of events as well as the way of linking those chunks into one chain of the corresponding thread using offsets. During the application execution, it may occur that some threads start recording events later than others. This scenario requires appropriate modifications and adjustments to the above approach. According to the previous approach, the header is the first block of data that is added to the trace file; it is written before flushing the first chunk of events. Thus, the header contains the information only regarding the started threads. In order to add pairs \emph{} of the late threads, we reserve a space for $64$ pairs (chunk of pairs) between chunks of events within the trace file. So, when one among those late threads wants to flush its buffer to the trace file, we add its pair \emph{} directly to the next free spot in the chunk of pairs. The chunks of pairs are binded with offset in the same way as chunks of events. Therefore, \eztrace{} does not have limitations on the number of threads per process and also processes. \subsection{Post-Mortem Analysis} We develop the functionality for analyzing the generated traces by capturing the procedure of the event recording mechanism. At first, \litl{} reads the trace header with the information regarding the buffer size, threads (the number of threads, tids, and offsets), and also pairs \emph{} that correspond to the late threads. Using this preliminary information, \litl{} allocates memory buffers for reading; the number of buffers equals the number of threads used during the recording phase, meaning one buffer per thread. Then, \litl{} loads chunks of events from the trace file into these buffers using pairs \emph{}. After processing the first chunks of events, \litl{} loads the buffers with the next ones using the information concerning their positions in the trace, which is given by the offsets. This procedure is recursive and stops when the symbol specifying the end of recording is reached. \section{Scalability vs. the Number of Traces} Usually binary tracing libraries generate one trace file per process. This means that for parallel applications with hundreds of \mpi{} processes the equal amount of trace files is created. This is one side of the problem. The other side appears while analyzing the applications execution due to the limitation on the number of trace files that can be opened and processed at the same time. Therefore, often those tracing libraries do not perform well and even crashes when the number of traces exceeds the Linux OS limit on the number of simultaneously opened files. In order to overcome the opened files limitation imposed by the Linux OS, one may increase the limit to the maximum possible value. However, this would temporarily solve the problem. Instead, we propose to create archives of traces during the post-mortem phase. More precisely, we suggest to merge multiple traces into a trace archive using the \texttt{litl\_merge} utility from \litl. \Cref{fig:storage_trace_merge} illustrates the structure of the new combined trace created by \texttt{litl\_merge}. The archives of traces preserve all information concerning each trace: headers, pairs \emph{}, and positioning of events chunks. They also contain new global headers that store the information regarding the amount of trace files in the archive and triples \emph{}; \emph{fid} stands for a file identifier; \emph{size} is a size of a particular trace file; \emph{offset} holds the position of a trace file within the archive of traces. Therefore, archives of traces not only solve the performance analysis problem, but also make the further analysis of the applications performance more convenient. One more useful feature provided by \litl{}, which is the opposite of \texttt{litl\_merge}, is a possibility to extract trace files from archives with the \texttt{litl\_split} utility. This utility can be applied when there is a need to analyze a particular trace or a set of traces among the merged ones. \begin{landscape} \input{@top_srcdir@/doc/tikz/event.storage.trace.file.merge} \end{landscape} \chapter{\litl{} in \fxt{} Applications} In this chapter, we present an approach of integrating \litl\ (as a possible replacement of \fxt{} and enable its usage in parallel with \fxt) into applications that already reply on \fxt{}. To simplify the process of integrating \litl\ into such applications, we map the functionality of \litl\ into the corresponding functionality from \fxt\ in \texttt{fxt.h} and \texttt{fut.h} headers; those files are part of \litl. As a result, developers of those applications can easier switch between two binary trace libraries and use \litl\ in conjunction with these two header files. Therefore, only minor changes are applied to the applications code. Even though \litl\ and \fxt\ target the same issue of gathering the information of the application execution, they have differences in the organization of the event recording as well as the event reading processes. In order to deal with those differences, we suggest to modify \fxt-related applications by following our suggestions. \section{Recording Events} The main difference between two trace libraries is in the organization of the initialization phase of the event recording process. So, in \fxt\ it is implemented as \lstset{language=C, caption={}, label={lstl:fxt}} \begin{lstlisting} fut_set_filename(filename); if (allow_flush && ...) { enable_fut_flush(); } fut_enable_tid_logging(); // IMPORTANT! fut_setup is AFTER all auxiliary functions if (fut_setup(buffer_size, FUT_KEYMASKALL, thread_id) < 0) { perror("fut_setup"); } \end{lstlisting} While in \litl\ the procedure is the following \lstset{language=C, caption={}, label={lstl:litl}} \begin{lstlisting} litl_trace = litl_write_init_trace(buffer_size); // the recording should be paused, because some further functions, // e.g. *_set_filename() can be intercepted litl_write_pause_recording(litl_trace); if (allow_flush && ...) { litl_write_buffer_flush_on(litl_trace); } litl_write_tid_recording_on(litl_trace); litl_write_set_filename(litl_trace, filename); // Do not forget to resume recording litl_write_resume_recording(litl_trace); \end{lstlisting} The mapping between the \litl\ and \fxt\ functions, which is implemented in \texttt{fut.h} and \texttt{fxt.h}, is organized as follow \begin{center} \begin{tabular}{lll} \hline\\ \texttt{fut\_setup()} & $\rightarrow$ & \texttt{litl\_write\_init\_trace()}\\ & & \texttt{litl\_write\_pause\_recording()}\\ \texttt{enable\_fut\_flush()} & $\rightarrow$ & \texttt{litl\_write\_buffer\_flush\_on()}\\ \texttt{fut\_enable\_tid\_logging()} & $\rightarrow$ & \texttt{litl\_write\_tid\_recording\_on()} \\ \texttt{fut\_set\_filename()} & $\rightarrow$ & \texttt{litl\_write\_set\_filename()}\\ & & \texttt{litl\_write\_resume\_recording()}\\ \hline\\ \end{tabular} \end{center} As a result, \litl\ can be used within the \fxt-related applications by simply replacing the \fxt\ code as follow \lstset{language=C, caption={}, label={lstl:litl_new}} \begin{lstlisting} // IMPORTANT! fut_setup is BEFORE all auxiliary functions if (fut_setup(buffer_size, FUT_KEYMASKALL, thread_id) < 0) { perror("fut_setup"); } fut_set_filename(filename); if (allow_flush && ...) { enable_fut_flush(); } fut_enable_tid_logging(); \end{lstlisting} Finally, the mapping between the \litl\ and \fxt\ event recording functions is organized as \begin{center} \begin{tabular}{lll} \hline\\ \texttt{FUT\_DO\_PROBEx()} & $\rightarrow$ & \texttt{litl\_write\_probe\_pack\_x()}\\ \texttt{FUT\_DO\_PROBE()} & $\rightarrow$ & \texttt{litl\_write\_probe\_pack\_0()}\\ \texttt{FUT\_DO\_PROBESTR()} & $\rightarrow$ & \texttt{litl\_write\_probe\_raw()}\\ \hline\\ \end{tabular} \end{center} For the successful and easy porting of \litl\ into your \fxt-related applications the above-mentioned suggestions needs to be incorporated. \chapter{Troubleshooting} If you encounter a bug or want some explanation about \litl{}, please contact and ask our development team on the development mailing list \begin{itemize} \item \url{litl-devel@fusionforge.int-evry.fr}. \end{itemize} \bibliographystyle{plain} \cleardoublepage \phantomsection \addcontentsline{toc}{chapter}{Bibliography} \small \bibliography{@top_srcdir@/doc/references} \normalsize \end{document} LiTL-litl-0.2/litl.pc.in000066400000000000000000000003211415666016500150240ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: LiTL Description: LiTL -- Lightweight Trace Library Version: @VERSION@ Libs: -L${libdir} -llitl Cflags: -I${includedir} LiTL-litl-0.2/src/000077500000000000000000000000001415666016500137225ustar00rootroot00000000000000LiTL-litl-0.2/src/CMakeLists.txt000066400000000000000000000015551415666016500164700ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/litl_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/litl_config.h ) add_library(litl SHARED litl_types.h litl_tools.h litl_tools.c litl_timer.h litl_timer.c litl_write.h litl_write.c litl_read.h litl_read.c litl_merge.h litl_merge.c litl_split.h litl_split.c ) target_link_libraries(litl PRIVATE pthread ) target_include_directories(litl PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) SET(LITL_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/litl_config.h litl_types.h litl_tools.h litl_timer.h litl_write.h litl_read.h litl_merge.h litl_split.h ) set_target_properties(litl PROPERTIES PUBLIC_HEADER "${LITL_HEADERS}") install( TARGETS litl LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) LiTL-litl-0.2/src/fut.h000066400000000000000000000066741415666016500147060ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file fut.h * \brief fut Provides a mapping of the LiTL APIs into the FxT APIs for easier * usage of LiTL in FxT-related applications * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #ifndef FUT_H_ #define FUT_H_ #include "fxt.h" /* "how" parameter values, analagous to "how" parameters to FKT */ #define FUT_ENABLE 0xCE03 /* for enabling probes with 1's in keymask */ #define FUT_DISABLE 0xCE04 /* for disabling probes with 1's in keymask */ #define FUT_SETMASK 0xCE05 /* for enabling 1's, disabling 0's in keymask */ /* Simple keymasks */ #define FUT_KEYMASK0 0x00000001 #define FUT_KEYMASK1 0x00000002 #define FUT_KEYMASK2 0x00000004 #define FUT_KEYMASK3 0x00000008 #define FUT_KEYMASK4 0x00000010 #define FUT_KEYMASK5 0x00000020 #define FUT_KEYMASK6 0x00000040 #define FUT_KEYMASK7 0x00000080 #define FUT_KEYMASK8 0x00000100 #define FUT_KEYMASK9 0x00000200 #define FUT_KEYMASK10 0x00000400 #define FUT_KEYMASK11 0x00000800 #define FUT_KEYMASK12 0x00001000 #define FUT_KEYMASK13 0x00002000 #define FUT_KEYMASK14 0x00004000 #define FUT_KEYMASK15 0x00008000 #define FUT_KEYMASK16 0x00010000 #define FUT_KEYMASK17 0x00020000 #define FUT_KEYMASK18 0x00040000 #define FUT_KEYMASK19 0x00080000 #define FUT_KEYMASK20 0x00100000 #define FUT_KEYMASK21 0x00200000 #define FUT_KEYMASK22 0x00400000 #define FUT_KEYMASK23 0x00800000 #define FUT_KEYMASK24 0x01000000 #define FUT_KEYMASK25 0x02000000 #define FUT_KEYMASK26 0x04000000 #define FUT_KEYMASK27 0x08000000 #define FUT_KEYMASK28 0x10000000 #define FUT_KEYMASK29 0x20000000 #define FUT_KEYMASK30 0x40000000 #define FUT_KEYMASK31 0x80000000 #define FUT_KEYMASKALL 0xffffffff #define FUT_GCC_INSTRUMENT_KEYMASK FUT_KEYMASK29 /* Fixed parameters of the fut coding scheme */ #define FUT_GENERIC_EXIT_OFFSET 0x100 /* exit this much above entry */ #define FUT_UNPAIRED_LIMIT_CODE 0xf000 /* all unpaired codes above this limit */ /* Codes for fut use */ #define FUT_SETUP_CODE 0xffff #define FUT_KEYCHANGE_CODE 0xfffe #define FUT_RESET_CODE 0xfffd #define FUT_CALIBRATE0_CODE 0xfffc #define FUT_CALIBRATE1_CODE 0xfffb #define FUT_CALIBRATE2_CODE 0xfffa #define FUT_THREAD_BIRTH_CODE 0xfff9 #define FUT_THREAD_DEATH_CODE 0xfff8 #define FUT_SET_THREAD_NAME_CODE 0xfff7 #define FUT_NEW_LWP_CODE 0xfff6 #define FUT_START_FLUSH_CODE 0xfff5 #define FUT_STOP_FLUSH_CODE 0xfff4 #define FUT_RQS_NEWLEVEL 0xffef #define FUT_RQS_NEWLWPRQ 0xffee #define FUT_RQS_NEWRQ 0xffed #define FUT_SWITCH_TO_CODE 0x31a #define FUT_MAIN_ENTRY_CODE 0x301 #define FUT_MAIN_EXIT_CODE 0x401 #endif /* FUT_H_ */ LiTL-litl-0.2/src/fxt.h000066400000000000000000000063401415666016500146770ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file fxt.h * \brief fxt Provides a mapping of the LiTL APIs into the FxT APIs for easier * usage of LiTL in FxT-related applications * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #ifndef FXT_H_ #define FXT_H_ #include #include #include "litl_types.h" #include "litl_write.h" #include "litl_read.h" typedef litl_write_trace_t* fxt_t; static fxt_t __trace; /* BEGIN -- Recording functions */ #define fut_setup(buffer_size, keymask, threadid) do { \ __trace = litl_write_init_trace(buffer_size); \ litl_write_pause_recording(__trace); \ }while(0) // finalizing traces #define fut_endup(filename) do { \ litl_write_finalize_trace(__trace); \ }while(0) #define fut_done(void) do { \ } while(0) #define fut_set_filename(filename) do { \ litl_write_set_filename(__trace, filename); \ litl_write_resume_recording(__trace); \ } while(0) #define enable_fut_flush() do { \ litl_write_buffer_flush_on(__trace); \ } while(0) #define disable_fut_flush() do { \ litl_write_buffer_flush_off(__trace); \ } while(0) #define fut_enable_tid_logging() do { \ litl_write_tid_recording_on(__trace); \ } while(0) #define fut_disable_tid_logging() do { \ litl_write_tid_recording_off(__trace); \ } while(0) /* END -- Recording functions */ /* BEGIN -- Events */ #define FUT_DO_PROBE0(code) \ do { \ litl_t*retval; \ litl_write_probe_pack_0(__trace, code, retval); \ assert(retval != NULL); \ } while(0) #define FUT_DO_PROBE1(code, arg1) \ do { \ litl_t* retval; \ litl_write_probe_pack_1(__trace, code, arg1, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE2(code, arg1, arg2) \ do { \ litl_t *retval; \ litl_write_probe_pack_2(__trace, code, arg1, arg2, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE3(code, arg1, arg2, arg3) \ do { \ litl_t *retval; \ litl_write_probe_pack_3(__trace, code, arg1, arg2, arg3, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE4(code, arg1, arg2, arg3, arg4) \ do { \ litl_t *retval; \ litl_write_probe_pack_4(__trace, code, arg1, arg2, arg3, arg4, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE5(code, arg1, arg2, arg3, arg4, arg5) \ do { \ litl_t *retval; \ litl_write_probe_pack_5(__trace, code, arg1, arg2, arg3, arg4, arg5, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE6(code, arg1, arg2, arg3, arg4, arg5, arg6) \ do { \ litl_t *retval; \ litl_write_probe_pack_6(__trace, code, arg1, arg2, arg3, arg4, arg5, arg6, retval); \ assert(retval != NULL); \ }while(0) #define FUT_DO_PROBE(code, ...) litl_write_probe_pack_0(__trace, code); #define FUT_DO_PROBESTR(code, str) litl_write_probe_raw(__trace, code, strlen(str), str) /* END -- Events */ #endif /* FXT_H_ */ LiTL-litl-0.2/src/litl_config.h.in000066400000000000000000000010271415666016500167710ustar00rootroot00000000000000#ifndef LITL_CONFIG_H #define LITL_CONFIG_H #cmakedefine USE_GETTID 1 #cmakedefine FORCE_32BIT 1 #if FORCE_32_BIT /* compile for 32bit architecture */ #define HAVE_32BIT 1 #else /* FORCE_32_BIT */ /* detect 32/64 bit architecture */ #ifndef SIZEOF_POINTER #define SIZEOF_POINTER @CMAKE_SIZEOF_VOID_P@ #endif #if (SIZEOF_POINTER == 4) /* 32bit arch */ #define HAVE_32BIT 1 #else /* 64bit arch */ #define HAVE_32BIT 0 #endif #endif #define CLOCK_GETTIME_AVAIL 1 #define VERSION "@PROJECT_VERSION@" #endif /* LITL_CONFIG_H */ LiTL-litl-0.2/src/litl_merge.c000066400000000000000000000175551415666016500162260ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_merge.h" static litl_trace_merge_t* __arch; static litl_trace_triples_t** __triples; /* * Sets a new name for the archive */ static void __litl_merge_set_archive_name(const char* filename) { int res __attribute__ ((__unused__)); // check whether the file name was set. If no, set it by default trace name if (filename == NULL ) res = asprintf(&__arch->filename, "/tmp/%s_%s", getenv("USER"), "litl_archive_1"); if (asprintf(&__arch->filename, "%s", filename) == -1) { perror("Error: Cannot set the filename for recording events!\n"); exit(EXIT_FAILURE); } } /* * Adds a trace header: * - The number of traces * - Triples: a file id, a file size, and an offset */ static void __litl_merge_add_archive_header() { int trace_in, res __attribute__ ((__unused__)); litl_med_size_t trace_index, process_index, general_header_size, process_header_size, global_header_size, nb_processes, total_nb_processes; litl_buffer_t header_buffer; total_nb_processes = 0; global_header_size = 0; general_header_size = sizeof(litl_general_header_t); process_header_size = sizeof(litl_process_header_t); // create an array of arrays of offsets __triples = (litl_trace_triples_t **) malloc( __arch->nb_traces * sizeof(litl_trace_triples_t *)); // read all header of traces and write them to the global header of the archive for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) { if ((trace_in = open(__arch->traces_names[trace_index], O_RDONLY)) < 0) { fprintf(stderr, "[litl_merge] Cannot open %s to read its header\n", __arch->traces_names[trace_index]); exit(EXIT_FAILURE); } // read the trace header header_buffer = (litl_buffer_t) malloc(general_header_size); res = read(trace_in, header_buffer, general_header_size); nb_processes = ((litl_general_header_t *) header_buffer)->nb_processes; __triples[trace_index] = (litl_trace_triples_t *) malloc( nb_processes * sizeof(litl_trace_triples_t)); // add a general header if (trace_index == 0) { sprintf((char*) ((litl_general_header_t *) __arch->buffer)->litl_ver, "%s", (char*) ((litl_general_header_t *) header_buffer)->litl_ver); sprintf((char*) ((litl_general_header_t *) __arch->buffer)->sysinfo, "%s", (char*) ((litl_general_header_t *) header_buffer)->sysinfo); global_header_size += general_header_size; __arch->buffer += general_header_size; } // read headers of processes res = read(trace_in, __arch->buffer, nb_processes * process_header_size); // find the trace size if (nb_processes == 1) { struct stat st; if (fstat(trace_in, &st)) { perror("Cannot apply fstat to the input trace files!"); exit(EXIT_FAILURE); } ((litl_process_header_t *) __arch->buffer)->trace_size = (litl_trace_size_t) st.st_size - general_header_size - process_header_size; } for (process_index = 0; process_index < nb_processes; process_index++) { __triples[trace_index][process_index].nb_processes = nb_processes; __triples[trace_index][process_index].position = global_header_size + (process_index + 1) * process_header_size - sizeof(litl_offset_t); __triples[trace_index][process_index].offset = ((litl_process_header_t *) __arch->buffer)->offset - general_header_size - nb_processes * process_header_size; __arch->buffer += process_header_size; } total_nb_processes += nb_processes; global_header_size += nb_processes * process_header_size; free(header_buffer); close(trace_in); } // update the number of processes ((litl_general_header_t *) __arch->buffer_ptr)->nb_processes = total_nb_processes; res = write(__arch->f_handle, __arch->buffer_ptr, global_header_size); __arch->general_offset += global_header_size; __arch->buffer = __arch->buffer_ptr; } /* * Creates and opens an archive for traces. * Allocates memory for the buffer */ static void __litl_merge_init_archive(const char* arch_name, char** traces_names, const int nb_traces) { __arch = (litl_trace_merge_t *) malloc(sizeof(litl_trace_merge_t)); // allocate buffer for read/write ops __arch->buffer_size = 16 * 1024 * 1024; // 16 MB __arch->buffer_ptr = (litl_buffer_t) calloc(__arch->buffer_size, 1); __arch->buffer = __arch->buffer_ptr; __arch->nb_traces = nb_traces; __arch->traces_names = traces_names; __arch->general_offset = 0; __litl_merge_set_archive_name(arch_name); // create an archive for trace files in rw-r-r- mode (0644) if ((__arch->f_handle = open(__arch->filename, O_WRONLY | O_CREAT, 0644)) < 0) { fprintf(stderr, "[litl_merge] Cannot open %s archive\n", __arch->filename); exit(EXIT_FAILURE); } // add a general archive header and also a set of process headers __litl_merge_add_archive_header(); } /* * Merges trace files. This is a modified version of the cat implementation * from the Kernighan & Ritchie book */ static void __litl_merge_create_archive() { int trace_in, res; litl_offset_t offset; litl_med_size_t trace_index, process_index, nb_processes; litl_trace_size_t header_offset, general_header_size, process_header_size; general_header_size = sizeof(litl_general_header_t); process_header_size = sizeof(litl_process_header_t); for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) { if ((trace_in = open(__arch->traces_names[trace_index], O_RDONLY)) < 0) { fprintf(stderr, "[litl_merge] Cannot open %s\n", __arch->traces_names[trace_index]); exit(EXIT_FAILURE); } // update offsets of processes nb_processes = __triples[trace_index][0].nb_processes; for (process_index = 0; process_index < nb_processes; process_index++) { lseek(__arch->f_handle, __triples[trace_index][process_index].position, SEEK_SET); offset = __triples[trace_index][process_index].offset + __arch->general_offset; res = write(__arch->f_handle, &offset, sizeof(litl_offset_t)); lseek(__arch->f_handle, __arch->general_offset, SEEK_SET); } // merge traces header_offset = general_header_size + nb_processes * process_header_size; lseek(trace_in, header_offset, SEEK_SET); // solution: Reading and writing blocks of data. Use the file size // to deal with the reading of the last block from the // traces while (1) { res = read(trace_in, __arch->buffer, __arch->buffer_size); if (res < 0) { perror("Cannot read the data from the traces!"); exit(EXIT_FAILURE); } res = write(__arch->f_handle, __arch->buffer, res); __arch->general_offset += res; if ((litl_size_t) res < __arch->buffer_size) break; } close(trace_in); } } /* * Frees the allocated memory */ static void __litl_merge_finalize_archive() { close(__arch->f_handle); // free offsets litl_med_size_t trace_index; for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) free(__triples[trace_index]); free(__triples); // free filenames free(__arch->filename); for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) free(__arch->traces_names[trace_index]); free(__arch->traces_names); free(__arch->buffer_ptr); __arch->buffer_ptr = NULL; __arch = NULL; } void litl_merge_traces(const char* arch_name, char** traces_names, const int nb_traces) { __litl_merge_init_archive(arch_name, traces_names, nb_traces); __litl_merge_create_archive(); __litl_merge_finalize_archive(); } LiTL-litl-0.2/src/litl_merge.h000066400000000000000000000020301415666016500162110ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #ifndef LITL_MERGE_H_ #define LITL_MERGE_H_ /** * \file litl_merge.h * \brief litl_merge Provides a set of functions for merging trace files into * an archive of traces * * \authors * Developers are : \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include "litl_types.h" /** * \defgroup litl_merge LiTL Merging Functions */ /** * \ingroup litl_merge * \brief Merges trace files into an archive. This is a modified version of the * implementation of the cat function from the Kernighan & Ritchie book * \param arch_name A name of an archive * \param traces_names An array of traces names * \param nb_traces A number of trace files to be composed into an archive */ void litl_merge_traces(const char* arch_name, char** traces_names, const int nb_traces); #endif /* LITL_MERGE_H_ */ LiTL-litl-0.2/src/litl_read.c000066400000000000000000000351361415666016500160350ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #include #include #include #include #include #include #include "litl_tools.h" #include "litl_read.h" /* * Initializes the trace header */ static void __litl_read_init_trace_header(litl_read_trace_t* trace) { int res; litl_size_t header_size, general_header_size; general_header_size = sizeof(litl_general_header_t); // read the trace header header_size = sizeof(litl_general_header_t); trace->header_buffer_ptr = (litl_buffer_t) malloc(header_size); if (!trace->header_buffer_ptr) { perror("Could not allocate memory for the trace header!"); exit(EXIT_FAILURE); } res = read(trace->f_handle, trace->header_buffer_ptr, header_size); // If the end of file is reached, then all data are read; res = 0. // Otherwise, res equals the number of elements (= 1) or the error // occurred and res = -1. if (res == -1) { perror("Could not read the trace header!"); exit(EXIT_FAILURE); } // init the trace header trace->header = (litl_general_header_t *) trace->header_buffer_ptr; // get the number of processes trace->nb_processes = trace->header->nb_processes; // relocate the header buffer header_size += trace->nb_processes * sizeof(litl_process_header_t); trace->header_buffer_ptr = (litl_buffer_t) realloc(trace->header_buffer_ptr, header_size); // read the trace header res = read(trace->f_handle, trace->header_buffer_ptr + general_header_size, header_size - general_header_size); if (res == -1) { perror("Could not read the trace header!"); exit(EXIT_FAILURE); } trace->header = (litl_general_header_t *) trace->header_buffer_ptr; trace->header_buffer = trace->header_buffer_ptr + general_header_size; } /* * Initializes the trace header, meaning it reads chunks with all pairs */ static void __litl_read_init_process_header(litl_read_trace_t* trace, litl_read_process_t* process) { // init the header structure litl_trace_size_t header_size; litl_med_size_t nb_threads = (process->header->header_nb_threads > NBTHREADS) ? process->header->header_nb_threads : NBTHREADS; header_size = (nb_threads + 1) * sizeof(litl_thread_pair_t); process->header_buffer_ptr = (litl_buffer_t) malloc(header_size); // read threads pairs (tid, offset) lseek(trace->f_handle, process->header->offset, SEEK_SET); header_size = (process->header->header_nb_threads + 1) * sizeof(litl_thread_pair_t); int res = read(trace->f_handle, process->header_buffer_ptr, header_size); if (res == -1) { perror("Could not read the trace header!"); exit(EXIT_FAILURE); } process->header_buffer = process->header_buffer_ptr; } /* * Reads another portion of pairs(tid, offset) from the trace file */ static void __litl_read_next_pairs_buffer(litl_read_trace_t* trace, litl_read_process_t* process, litl_offset_t offset) { lseek(trace->f_handle, offset, SEEK_SET); litl_med_size_t nb_threads = (process->nb_threads - process->header->header_nb_threads) > NBTHREADS ? NBTHREADS : (process->nb_threads - process->header->header_nb_threads); int res = read(trace->f_handle, process->header_buffer_ptr, (nb_threads + 1) * sizeof(litl_thread_pair_t)); process->header_buffer = process->header_buffer_ptr; if (res == -1) { perror( "Could not read the next part of pairs (tid, offset) from the trace file!"); exit(EXIT_FAILURE); } } /* * Initializes buffers -- one buffer per thread. */ static void __litl_read_init_threads(litl_read_trace_t* trace, litl_read_process_t* process) { litl_med_size_t thread_index, size; litl_thread_pair_t *thread_pair; size = sizeof(litl_thread_pair_t); // init nb_threads and allocate memory process->nb_threads = process->header->nb_threads; process->threads = (litl_read_thread_t **) malloc( process->nb_threads * sizeof(litl_read_thread_t*)); // increase a bit the buffer size 'cause of the event's tail and the offset process->header->buffer_size += __litl_get_reg_event_size(LITL_MAX_PARAMS) + __litl_get_reg_event_size(0); for (thread_index = 0; thread_index < process->nb_threads; thread_index++) { // allocate thread structure process->threads[thread_index] = (litl_read_thread_t *) malloc( sizeof(litl_read_thread_t)); process->threads[thread_index]->thread_pair = (litl_thread_pair_t *) malloc( sizeof(litl_thread_pair_t)); process->threads[thread_index]->buffer_ptr = (litl_buffer_t) malloc( process->header->buffer_size); // read pairs (tid, offset) thread_pair = (litl_thread_pair_t *) process->header_buffer; // deal with slots of pairs if ((thread_pair->tid == 0) && (thread_pair->offset != 0)) { __litl_read_next_pairs_buffer( trace, process, process->header->offset + thread_pair->offset); thread_pair = (litl_thread_pair_t *) process->header_buffer; } // end of reading pairs if ((thread_pair->tid == 0) && (thread_pair->offset == 0)) break; process->threads[thread_index]->thread_pair->tid = thread_pair->tid; // use two offsets: process and thread. Process offset for a position // of thread pairs; thread offset for a position of events process->threads[thread_index]->thread_pair->offset = thread_pair->offset + process->header->offset; // read chunks of data // use offsets in order to access a chuck of data that corresponds to // each thread lseek(trace->f_handle, process->threads[thread_index]->thread_pair->offset, SEEK_SET); int res = read(trace->f_handle, process->threads[thread_index]->buffer_ptr, process->header->buffer_size); if (res == -1) { perror("Could not read the first partition of data from the trace file!"); exit(EXIT_FAILURE); } process->threads[thread_index]->buffer = process->threads[thread_index]->buffer_ptr; process->threads[thread_index]->tracker = process->header->buffer_size; process->threads[thread_index]->offset = 0; process->header_buffer += size; } } /* * Opens a trace */ litl_read_trace_t* litl_read_open_trace(const char* filename) { litl_read_trace_t *trace = (litl_read_trace_t *) malloc( sizeof(litl_read_trace_t)); // open a trace file if ((trace->f_handle = open(filename, O_RDONLY)) < 0) { fprintf(stderr, "Cannot open %s\n", filename); exit(EXIT_FAILURE); } // init the trace header __litl_read_init_trace_header(trace); return trace; } /* * Initializes processes as trace may store multiple processes */ void litl_read_init_processes(litl_read_trace_t* trace) { trace->processes = (litl_read_process_t **) malloc( trace->nb_processes * sizeof(litl_read_process_t*)); litl_med_size_t process_index, size; size = sizeof(litl_process_header_t); for (process_index = 0; process_index < trace->nb_processes; process_index++) { trace->processes[process_index] = (litl_read_process_t *) malloc( sizeof(litl_read_process_t)); // read the process header trace->processes[process_index]->header = (litl_process_header_t *) trace->header_buffer; trace->header_buffer += size; trace->processes[process_index]->cur_index = -1; trace->processes[process_index]->is_initialized = 0; // init the process header __litl_read_init_process_header(trace, trace->processes[process_index]); // init buffers of events: one buffer per thread __litl_read_init_threads(trace, trace->processes[process_index]); } } /* * Returns a pointer to the trace header */ litl_general_header_t* litl_read_get_trace_header(litl_read_trace_t* trace) { return trace->header; } /* * Returns a pointer to the process header */ litl_process_header_t* litl_read_get_process_header( litl_read_process_t* process) { return process->header; } /* * Sets the buffer size */ void litl_read_set_buffer_size(litl_read_trace_t* trace, const litl_size_t buf_size) { litl_med_size_t i; for (i = 0; i < trace->nb_processes; i++) trace->processes[i]->header->buffer_size = buf_size; } /* * Returns the buffer size */ litl_size_t litl_read_get_buffer_size(litl_read_trace_t* trace) { return trace->processes[0]->header->buffer_size; } /* * Reads a next portion of events from the trace file to the buffer */ static void __litl_read_next_buffer(litl_read_trace_t* trace, litl_read_process_t* process, litl_read_thread_t* thread) { lseek(trace->f_handle, process->header->offset + thread->thread_pair->offset, SEEK_SET); thread->offset = 0; // read portion of next events int res = read(trace->f_handle, thread->buffer_ptr, process->header->buffer_size); if (res == -1) { perror("Could not read the next part of the trace file!"); exit(EXIT_FAILURE); } thread->buffer = thread->buffer_ptr; thread->tracker = thread ->offset + process->header->buffer_size; } /* * Resets the thread buffers of a given process */ void litl_read_reset_process(litl_read_process_t* process) { litl_med_size_t thread_index; for (thread_index = 0; thread_index < process->nb_threads; thread_index++) process->threads[thread_index]->buffer = process->threads[thread_index]->buffer_ptr; } /* * Reads an event */ static litl_read_event_t* __litl_read_next_thread_event( litl_read_trace_t* trace, litl_read_process_t* process, litl_read_thread_t* thread) { litl_data_t to_be_loaded; litl_t* event; litl_buffer_t buffer; buffer = thread->buffer; to_be_loaded = 0; if (!buffer) { thread->cur_event.event = NULL; return NULL ; } event = (litl_t *) buffer; // While reading events from the buffer, there can be two situations: // 1. The situation when the buffer contains exact number of events; // 2. The situation when only a part of the last event is loaded. // Check whether the main four components (tid, time, code, nb_params) are // loaded. // Check whether all arguments are loaded. // If any of these cases is not true, the next part of the trace plus // the current event is loaded to the buffer litl_size_t remaining_size = thread->tracker - thread->offset; if (remaining_size < __litl_get_reg_event_size(0)) { // this event is truncated. We can't even read the nb_param field to_be_loaded = 1; } else { // The nb_param (or size) field is available. Let's check whether // the event is truncated litl_med_size_t event_size = __litl_get_gen_event_size(event); if (remaining_size < event_size) to_be_loaded = 1; } // fetch the next block of data from the trace if (to_be_loaded) { __litl_read_next_buffer(trace, process, thread); buffer = thread->buffer; event = (litl_t *) buffer; } to_be_loaded = 0; // event that stores tid and offset if (event->code == LITL_OFFSET_CODE) { if (event->parameters.offset.offset != 0) { thread->thread_pair->offset = event->parameters.offset.offset; to_be_loaded = 1; } else { buffer = NULL; thread->cur_event.event = NULL; return NULL ; } } // fetch the next block of data from the trace if (to_be_loaded) { __litl_read_next_buffer(trace, process, thread); buffer = thread->buffer; event = (litl_t *) buffer; } // move pointer to the next event and update __offset litl_med_size_t evt_size = __litl_get_gen_event_size(event); thread->buffer += evt_size; thread->offset += evt_size; thread->cur_event.event = event; thread->cur_event.tid = thread->thread_pair->tid; return &thread->cur_event; } litl_read_event_t* litl_read_next_thread_event(litl_read_trace_t* trace, litl_read_process_t* process, litl_read_thread_t* thread) { return __litl_read_next_thread_event(trace, process, thread); } /* * Searches for the next event inside the trace */ litl_read_event_t* litl_read_next_process_event(litl_read_trace_t* trace, litl_read_process_t* process) { litl_med_size_t thread_index; litl_time_t min_time = -1; if (!process->is_initialized) { for (thread_index = 0; thread_index < process->nb_threads; thread_index++) __litl_read_next_thread_event(trace, process, process->threads[thread_index]); process->cur_index = -1; process->is_initialized = 1; } // read the next event from the buffer if (process->cur_index != -1) __litl_read_next_thread_event(trace, process, process->threads[process->cur_index]); int found = 0; for (thread_index = 0; thread_index < process->nb_threads; thread_index++) { litl_read_event_t *evt = LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index); if ( evt && evt->event && (LITL_READ_GET_TIME(evt) < min_time)) { found = 1; min_time = LITL_READ_GET_TIME(evt); process->cur_index = thread_index; } } if (found) return LITL_READ_GET_CUR_EVENT(process); return NULL ; } /* * Reads the next event from a trace */ litl_read_event_t* litl_read_next_event(litl_read_trace_t* trace) { litl_med_size_t process_index; litl_read_event_t* event = NULL; for (process_index = 0; process_index < trace->nb_processes; process_index++) { event = litl_read_next_process_event(trace, trace->processes[process_index]); if (event != NULL ) break; } return event; } /* * Closes the trace and frees the buffer */ void litl_read_finalize_trace(litl_read_trace_t* trace) { litl_med_size_t process_index, thread_index; // close the file close(trace->f_handle); trace->f_handle = -1; // free traces for (process_index = 0; process_index < trace->nb_processes; process_index++) { for (thread_index = 0; thread_index < trace->processes[process_index]->nb_threads; thread_index++) { free(trace->processes[process_index]->threads[thread_index]->thread_pair); free(trace->processes[process_index]->threads[thread_index]->buffer_ptr); free(trace->processes[process_index]->threads[thread_index]); } free(trace->processes[process_index]->threads); free(trace->processes[process_index]->header_buffer_ptr); free(trace->processes[process_index]); } // free a trace structure free(trace->processes); free(trace->header_buffer_ptr); free(trace); // set the trace pointer to NULL trace = NULL; } LiTL-litl-0.2/src/litl_read.h000066400000000000000000000430631415666016500160400ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #ifndef LITL_READ_H_ #define LITL_READ_H_ /** * \file litl_read.h * \brief litl_read Provides a set of functions for reading events from a * regular trace file or an archive of traces * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include "litl_types.h" /** * \defgroup litl_read LiTL Reading Functions */ /** * \defgroup litl_read_init Initialization Functions * \ingroup litl_read */ /** * \defgroup litl_read_main Functions for Reading Events * \ingroup litl_read */ /** * \defgroup litl_read_process Functions for Processing Events * \ingroup litl_read */ /** * \ingroup litl_read_init * \brief Opens a trace and reads the first portion of data (trace header) to the buffer * \param filename A filename * \return A pointer to the trace object. NULL in case of failure */ litl_read_trace_t* litl_read_open_trace(const char* filename); /** * \ingroup litl_read_init * \brief Initializes the event reading structure * \param trace A pointer to the trace object */ void litl_read_init_processes(litl_read_trace_t* trace); /** * \ingroup litl_read_init * \brief Returns a pointer to the trace header * \param trace A pointer to the trace object * \return A pointer to the trace header */ litl_general_header_t* litl_read_get_trace_header(litl_read_trace_t* trace); /** * \ingroup litl_read_init * \brief Returns a pointer to the process header * \param process A pointer to the process object * \return A pointer to the trace header */ litl_process_header_t* litl_read_get_process_header( litl_read_process_t* process); /** * \ingroup litl_read_init * \brief Sets the buffer size * \param trace A pointer to the trace object * \param buf_size A buffer size (in Byte) */ void litl_read_set_buffer_size(litl_read_trace_t* trace, const litl_size_t buf_size); /** * \ingroup litl_read_init * \brief Returns the buffer size * \param trace A pointer to the trace object * \return A buffer size (in Byte) */ litl_size_t litl_read_get_buffer_size(litl_read_trace_t* trace); /** * \ingroup litl_read_main * \brief Resets the trace pointer * \param process A pointer to the process object */ void litl_read_reset_process(litl_read_process_t* process); /** * \ingroup litl_read_main * \brief Reads the next event from a trace * \param trace A pointer to the trace object * \param process A pointer to the process object */ litl_read_event_t* litl_read_next_process_event(litl_read_trace_t* trace, litl_read_process_t* process); /** * \ingroup litl_read_main * \brief Reads the next event from a trace * \param trace A pointer to the trace object * \param process A pointer to the process object * \param thread A pointer to the thread object */ litl_read_event_t* litl_read_next_thread_event(litl_read_trace_t* trace, litl_read_process_t* process, litl_read_thread_t* thread); /** * \ingroup litl_read_main * \brief Reads the next event from a trace file * \param trace A pointer to the trace object */ litl_read_event_t* litl_read_next_event(litl_read_trace_t* trace); /** * \ingroup litl_read_main * \brief Closes the trace and frees the allocated memory * \param trace A pointer to the trace object */ void litl_read_finalize_trace(litl_read_trace_t* trace); /*** Internal-use macros ***/ /* * For internal use only * Initializes a pointer for browsing the parameters of an event */ #define __LITL_READ_INIT_PTR(evt, _ptr_) \ do { \ if(LITL_READ_GET_TYPE(evt) == LITL_TYPE_REGULAR) \ _ptr_ = &LITL_READ_REGULAR(evt)->param[0]; \ else if(LITL_READ_GET_TYPE(evt) == LITL_TYPE_PACKED) \ _ptr_ = &(LITL_READ_PACKED(evt))->param[0]; \ } while(0) #if DEBUG #define __LITL_CHECK_EVENT_SIZE(evt, _ptr_) \ do{ \ void* base_ptr; \ __LITL_READ_INIT_PTR(evt, base_ptr); \ int expected_size=0; \ if(LITL_READ_GET_TYPE(evt) == LITL_TYPE_REGULAR){ \ expected_size = LITL_READ_REGULAR(evt)->nb_params * sizeof(litl_param_t); \ int actual_size= ((char*)_ptr_)-((char*)base_ptr); \ if(actual_size != expected_size){ \ fprintf(stderr, "[LiTL] Warning: parameters take %d bytes, but %d bytes were read!\n", expected_size, actual_size); \ abort(); \ } \ } else { \ expected_size = LITL_READ_PACKED(evt)->size; \ int actual_size= ((char*)_ptr_)-((char*)base_ptr); \ if(actual_size != expected_size){ \ fprintf(stderr, "[LiTL] Warning: parameters take %d bytes, but %d bytes were read!\n", expected_size, actual_size); \ abort(); \ } \ } \ }while(0) #else #define __LITL_CHECK_EVENT_SIZE(evt, _ptr_) do { }while(0) #endif /* * For internal use only * Returns the next parameter in an event */ #define __LITL_READ_GET_ARG(evt, _ptr_, arg) \ do { \ if(LITL_READ_GET_TYPE(evt) == LITL_TYPE_REGULAR) \ __LITL_READ_GET_ARG_REGULAR(_ptr_, arg); \ else \ __LITL_READ_GET_ARG_PACKED(_ptr_, arg); \ } while(0) /* * For internal use only * Returns the next parameter in a regular event */ #define __LITL_READ_GET_ARG_REGULAR(_ptr_, arg) do { \ arg = (typeof(arg)) *(litl_param_t*)_ptr_; \ (litl_param_t*)_ptr_++; \ } while(0) /* * For internal use only * Returns the next parameter in a packed event */ #define __LITL_READ_GET_ARG_PACKED(_ptr_, arg) do { \ memcpy(&arg, _ptr_, sizeof(arg)); \ _ptr_ = ((char*)_ptr_)+sizeof(arg); \ } while(0) /*** functions for reading events ***/ /** * \ingroup litl_read_process * \brief Returns a current event of a given thread * \param process An event reading object * \param thread_index An index of a given thread */ #define LITL_READ_GET_CUR_EVENT_PER_THREAD(process, thread_index) \ (&(process)->threads[(thread_index)]->cur_event) /** * \ingroup litl_read_process * \brief Returns a current event of a given trace * \param process An event reading object */ #define LITL_READ_GET_CUR_EVENT(process) \ LITL_READ_GET_CUR_EVENT_PER_THREAD(process, (process)->cur_index) /** * \ingroup litl_read_process * \brief Returns a thread id of a given event * \param read_event An event */ #define LITL_READ_GET_TID(read_event) (read_event)->tid /** * \ingroup litl_read_process * \brief Returns a time stamp of a given event * \param read_event An event */ #define LITL_READ_GET_TIME(read_event) (read_event)->event->time /** * \ingroup litl_read_process * \brief Returns a type of a given event * \param read_event An event */ #define LITL_READ_GET_TYPE(read_event) (read_event)->event->type /** * \ingroup litl_read_process * \brief Returns a code of a given event * \param read_event An event */ #define LITL_READ_GET_CODE(read_event) (read_event)->event->code /** * \ingroup litl_read_process * \brief Returns a size and parameters in the string format of a raw event * \param read_event An event */ #define LITL_READ_RAW(read_event) (&(read_event)->event->parameters.raw) /** * \ingroup litl_read_process * \brief Returns a size and a list of parameters of a regular event * \param read_event An event */ #define LITL_READ_REGULAR(read_event) (&(read_event)->event->parameters.regular) /** * \ingroup litl_read_process * \brief Returns a size and a list of parameters of a packed event * \param read_event An event */ #define LITL_READ_PACKED(read_event) (&(read_event)->event->parameters.packed) /** * \ingroup litl_read_process * \brief Returns a size and an offset of an event of type offset * \param read_event An event */ #define LITL_READ_OFFSET(read_event) (&(read_event)->event->parameters.offset) /** * \ingroup litl_read_process * \brief Assigns the first parameter of p_evt to param1 * \param p_evt A pointer to an event * \param param1 1st parameter for this event */ #define litl_read_get_param_1(p_evt, \ param1) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 2 parameters of p_evt to param1 and param2 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event */ #define litl_read_get_param_2(p_evt, \ param1, \ param2) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 3 parameters of p_evt to param1, ..., param3 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event */ #define litl_read_get_param_3(p_evt, \ param1, \ param2, \ param3) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 4 parameters of p_evt to param1, ..., param4 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event */ #define litl_read_get_param_4(p_evt, \ param1, \ param2, \ param3, \ param4) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 5 parameters of p_evt to param1, ..., param5 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event */ #define litl_read_get_param_5(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 6 parameters of p_evt to param1, ..., param6 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event */ #define litl_read_get_param_6(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param6); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 7 parameters of p_evt to param1, ..., param7 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event */ #define litl_read_get_param_7(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param6); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param7); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 8 parameters of p_evt to param1, ..., param8 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event */ #define litl_read_get_param_8(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param6); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param7); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param8); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 9 parameters of p_evt to param1, ..., param9 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event */ #define litl_read_get_param_9(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8, \ param9) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param6); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param7); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param8); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param9); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) /** * \ingroup litl_read_process * \brief Assigns the first 10 parameters of p_evt to param1, ..., param10 * \param p_evt A pointer to an event * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event * \param param10 10th parameter for this event */ #define litl_read_get_param_10(p_evt, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8, \ param9, \ param10) \ do { \ void* _ptr_; \ __LITL_READ_INIT_PTR(p_evt, _ptr_); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param1); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param2); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param3); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param4); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param5); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param6); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param7); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param8); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param9); \ __LITL_READ_GET_ARG(p_evt, _ptr_, param10); \ __LITL_CHECK_EVENT_SIZE(p_evt, _ptr_); \ } while(0) #endif /* LITL_READ_H_ */ LiTL-litl-0.2/src/litl_split.c000066400000000000000000000116371415666016500162550ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #define _GNU_SOURCE #include #include #include #include #include "litl_split.h" static litl_trace_split_t* __arch; /* * Opens an archive of traces */ static void __litl_split_open_archive(const char *arch_name) { __arch = malloc(sizeof(litl_trace_split_t)); // open an archive of traces if ((__arch->f_handle = open(arch_name, O_RDONLY)) < 0) { fprintf(stderr, "Cannot open %s\n", arch_name); exit(EXIT_FAILURE); } // allocate buffer for read/write ops __arch->buffer_size = 16 * 1024 * 1024; // 16 MB __arch->buffer = (litl_buffer_t) malloc(__arch->buffer_size); } /* * Initializes a structure that stores triples from the trace header */ static void __litl_split_read_header() { int res __attribute__ ((__unused__)); litl_size_t header_size, general_header_size; general_header_size = sizeof(litl_general_header_t); // read a general header header_size = general_header_size; __arch->header_buffer_ptr = (litl_buffer_t) malloc(header_size); res = read(__arch->f_handle, __arch->header_buffer_ptr, header_size); __arch->header_buffer = __arch->header_buffer_ptr; // get the number of processes __arch->trace_header = (litl_general_header_t *) __arch->header_buffer; __arch->nb_processes = __arch->trace_header->nb_processes; if (__arch->nb_processes == 1) { printf( "The given trace is not an archive. Therefore, there is nothing to split.\n"); exit(EXIT_SUCCESS); } // Yes, we work with an archive of trace. So, we increase the header size // and relocate the header buffer header_size += __arch->nb_processes * sizeof(litl_process_header_t); __arch->header_buffer_ptr = (litl_buffer_t) realloc(__arch->header_buffer_ptr, header_size); // read headers of all processes res = read(__arch->f_handle, __arch->header_buffer_ptr + general_header_size, header_size - general_header_size); if (res == -1) { perror("Could not read the archive header!"); exit(EXIT_FAILURE); } __arch->header_buffer = __arch->header_buffer_ptr; __arch->trace_header = (litl_general_header_t *) __arch->header_buffer; __arch->header_buffer += general_header_size; // for splitting: one process into one trace file __arch->trace_header->nb_processes = 1; } /* * Writes each trace from an archive into a separate trace file */ static void __litl_split_extract_traces(const char *dir) { int trace_out, res __attribute__ ((__unused__)); char* trace_name; litl_size_t buffer_size; litl_med_size_t general_header_size, process_header_size; general_header_size = sizeof(litl_general_header_t); process_header_size = sizeof(litl_process_header_t); while (__arch->nb_processes-- != 0) { // get a process header __arch->process_header = (litl_process_header_t *) __arch->header_buffer; __arch->header_buffer += process_header_size; res = asprintf(&trace_name, "%s/%s", dir, __arch->process_header->process_name); // create and open a new trace file if ((trace_out = open(trace_name, O_WRONLY | O_CREAT, 0644)) < 0) { fprintf(stderr, "Cannot create and open %s\n", __arch->process_header->process_name); exit(EXIT_FAILURE); } // write a general trace header res = write(trace_out, __arch->trace_header, general_header_size); // write a process header buffer_size = __arch->process_header->offset; __arch->process_header->offset = general_header_size + process_header_size; res = write(trace_out, __arch->process_header, process_header_size); // set a file pointer to the position of the current process lseek(__arch->f_handle, buffer_size, SEEK_SET); // read data and write to a separate trace while (__arch->process_header->trace_size) { buffer_size = __arch->process_header->trace_size > __arch->buffer_size ? __arch->buffer_size : __arch->process_header->trace_size; res = read(__arch->f_handle, __arch->buffer, buffer_size); res = write(trace_out, __arch->buffer, buffer_size); __arch->process_header->trace_size -= buffer_size; } free(trace_name); close(trace_out); } } /* * Closes the archive and free the allocated memory */ static void __litl_split_close_archive() { close(__arch->f_handle); __arch->f_handle = -1; free(__arch->header_buffer_ptr); free(__arch->buffer); free(__arch); } void litl_split_archive(const char *arch_name, const char *output_dir) { // open an archive of traces and allocate memory for a buffer __litl_split_open_archive(arch_name); // get info from the archive's header __litl_split_read_header(); // split the archive __litl_split_extract_traces(output_dir); // close the archive and free the allocated memory __litl_split_close_archive(); } LiTL-litl-0.2/src/litl_split.h000066400000000000000000000015561415666016500162610ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #ifndef LITL_SPLIT_H_ #define LITL_SPLIT_H_ /** * \file litl_split.h * \brief litl_split Provides a set of functions for extracting trace files * from an archive of traces * * \authors * Developers are : \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include "litl_types.h" /** * \defgroup litl_split LiTL Splitting Functions */ /** * \ingroup litl_split * \brief Extracts each trace from an archive into a separate trace file * \param arch_name A name of an archive * \param output_dir A path to the directory with extracted traces */ void litl_split_archive(const char *arch_name, const char *output_dir); #endif /* LITL_SPLIT_H_ */ LiTL-litl-0.2/src/litl_timer.c000066400000000000000000000176441415666016500162460ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #include #include #include #include #include #include "litl_timer.h" litl_time_t litl_get_time_none(); static void __litl_time_ticks_initialize(); #define ERROR_TIMER_NOT_AVAILABLE() do { \ fprintf(stderr, "Trying to use timer function %s, but it is not available on this platform\n",__FUNCTION__); \ abort(); \ } while(0) // Choose the default timing method #if CLOCK_GETTIME_AVAIL #ifdef CLOCK_MONOTONIC_RAW #define TIMER_DEFAULT litl_get_time_monotonic_raw #else #define TIMER_DEFAULT litl_get_time_monotonic #endif // CLOCK_MONOTONIC_RAW #else // CLOCK_GETTIME_AVAIL #define TIMER_DEFAULT litl_get_time_ticks #endif // CLOCK_GETTIME_AVAIL /* * Selected timing method */ litl_timing_method_t litl_get_time = TIMER_DEFAULT; /* * Benchmarks function f and returns the number of calls to f that can be done * in 100 microseconds */ static unsigned __litl_time_benchmark_generic(litl_timing_method_t f) { unsigned i = 0; unsigned threshold = 100000; // how many calls to f() in 100 microseconds ? litl_time_t t1, t2; t1 = f(); do { t2 = f(); i++; } while (t2 - t1 < threshold); return i; } /* * Selects the most efficient timing method */ static void __litl_time_benchmark() { unsigned best_score = 0; unsigned cur_score; #define RUN_BENCHMARK(_func_) do { \ cur_score = __litl_time_benchmark_generic(_func_); \ if(cur_score > best_score) { \ best_score = cur_score; \ litl_set_timing_method(_func_); \ } \ }while(0) #if CLOCK_GETTIME_AVAIL #ifdef CLOCK_MONOTONIC_RAW RUN_BENCHMARK(litl_get_time_monotonic_raw); #endif #ifdef CLOCK_MONOTONIC RUN_BENCHMARK(litl_get_time_monotonic); #endif #ifdef CLOCK_REALTIME RUN_BENCHMARK(litl_get_time_realtime); #endif #ifdef CLOCK_PROCESS_CPUTIME_ID RUN_BENCHMARK(litl_get_time_process_cputime); #endif #ifdef CLOCK_THREAD_CPUTIME_ID RUN_BENCHMARK(litl_get_time_thread_cputime); #endif #endif /* CLOCK_GETTIME_AVAIL */ #if defined(__x86_64__) || defined(__i386) __litl_time_ticks_initialize(); RUN_BENCHMARK(litl_get_time_ticks); #endif printf("[LiTL] selected timing method:"); #if CLOCK_GETTIME_AVAIL #ifdef CLOCK_MONOTONIC_RAW if(litl_get_time == litl_get_time_monotonic_raw) printf("monotonic_raw\n"); #endif #ifdef CLOCK_MONOTONIC if(litl_get_time == litl_get_time_monotonic) printf("monotonic\n"); #endif #ifdef CLOCK_REALTIME if(litl_get_time == litl_get_time_realtime) printf("realtime\n"); #endif #ifdef CLOCK_PROCESS_CPUTIME_ID if(litl_get_time == litl_get_time_process_cputime) printf("process_cputime\n"); #endif #ifdef CLOCK_THREAD_CPUTIME_ID if(litl_get_time == litl_get_time_thread_cputime) printf("thread_cputime\n"); #endif #endif /* CLOCK_GETTIME_AVAIL */ #if defined(__x86_64__) || defined(__i386) if(litl_get_time == litl_get_time_ticks) printf("ticks\n"); #endif } /* * Initializes the timing mechanism */ void litl_time_initialize() { char* time_str = getenv("LITL_TIMING_METHOD"); if (time_str) { if (strcmp(time_str, "monotonic_raw") == 0) { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW)) litl_set_timing_method(litl_get_time_monotonic_raw); #else goto not_available; #endif } else if (strcmp(time_str, "monotonic") == 0) { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC)) litl_set_timing_method(litl_get_time_monotonic); #else goto not_available; #endif } else if (strcmp(time_str, "realtime") == 0) { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_REALTIME)) litl_set_timing_method(litl_get_time_realtime); #else goto not_available; #endif } else if (strcmp(time_str, "process_cputime") == 0) { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_PROCESS_CPUTIME_ID)) litl_set_timing_method(litl_get_time_process_cputime); #else goto not_available; #endif } else if (strcmp(time_str, "thread_cputime") == 0) { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_THREAD_CPUTIME_ID)) litl_set_timing_method(litl_get_time_thread_cputime); #else goto not_available; #endif } else if (strcmp(time_str, "ticks") == 0) { #if defined(__x86_64__) || defined(__i386) litl_set_timing_method(litl_get_time_ticks); /* dry run to make sure that the initialization process is done */ litl_get_time_ticks(); #else goto not_available; #endif } else if (strcmp(time_str, "none") == 0) { litl_set_timing_method(litl_get_time_none); } else if (strcmp(time_str, "best") == 0) { __litl_time_benchmark(); } else { fprintf(stderr, "Unknown timining method: '%s'\n", time_str); abort(); } } return; not_available: __attribute__ ((__unused__)) fprintf(stderr, "Timing function '%s' not available on this system\n", time_str); abort(); } /* * Returns -1 if none of timings is available. Otherwise, it returns 0 */ int litl_set_timing_method(litl_timing_method_t callback) { if (!callback) return -1; litl_get_time = callback; if(callback == litl_get_time_ticks) { __litl_time_ticks_initialize(); } return 0; } #if CLOCK_GETTIME_AVAIL static inline litl_time_t __litl_get_time_generic(clockid_t clk_id) { litl_time_t time; struct timespec tp; clock_gettime(clk_id, &tp); time = 1000000000 * tp.tv_sec + tp.tv_nsec; return time; } #endif /* * Uses clock_gettime(CLOCK_MONOTONIC_RAW) */ litl_time_t litl_get_time_monotonic_raw() { #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW)) return __litl_get_time_generic(CLOCK_MONOTONIC_RAW); #else ERROR_TIMER_NOT_AVAILABLE() ; return -1; #endif } /* * Uses clock_gettime(CLOCK_MONOTONIC) */ litl_time_t litl_get_time_monotonic() { #if CLOCK_GETTIME_AVAIL return __litl_get_time_generic(CLOCK_MONOTONIC); #else ERROR_TIMER_NOT_AVAILABLE() ; return -1; #endif } /* * Uses clock_gettime(CLOCK_REALTIME) */ litl_time_t litl_get_time_realtime() { #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_REALTIME)) return __litl_get_time_generic(CLOCK_REALTIME); #else ERROR_TIMER_NOT_AVAILABLE() ; return -1; #endif } /* * Uses clock_gettime(CLOCK_PROCESS_CPUTIME_ID) */ litl_time_t litl_get_time_process_cputime() { #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_PROCESS_CPUTIME_ID)) return __litl_get_time_generic(CLOCK_PROCESS_CPUTIME_ID); #else ERROR_TIMER_NOT_AVAILABLE() ; return -1; #endif } /* * Uses clock_gettime(CLOCK_THREAD_CPUTIME_ID) */ litl_time_t litl_get_time_thread_cputime() { #if (defined(CLOCK_GETTIME_AVAIL) && defined(CLOCK_THREAD_CPUTIME_ID)) return __litl_get_time_generic(CLOCK_THREAD_CPUTIME_ID); #else ERROR_TIMER_NOT_AVAILABLE() ; return -1; #endif } litl_time_t litl_get_time_none() { return 0; } static int ticks_initialized = 0; static litl_time_t __ticks_per_sec = 0; /* * Uses CPU specific register (for instance, rdtsc for X86* processors) */ litl_time_t litl_get_time_ticks() { #ifdef __x86_64__ // This is a copy of rdtscll function from asm/msr.h #define ticks(val) do { \ uint32_t __a,__d; \ asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ (val) = ((litl_time_t)__a) | (((litl_time_t)__d)<<32); \ } while(0) #elif defined(__i386) #define ticks(val) \ __asm__ volatile("rdtsc" : "=A" (val)) #else ERROR_TIMER_NOT_AVAILABLE(); #define ticks(val) (val) = -1 #endif litl_time_t time; ticks(time); return time * 1e9 / __ticks_per_sec; } /* initialize the ticks timer */ static void __litl_time_ticks_initialize() { if (!ticks_initialized) { /* since ticks return a timestamp measured in clock cycles, * we need to be able to convert it to ns */ litl_time_t init_start, init_end; /* how many cycles in 1 second ? */ ticks(init_start); usleep(1000000); ticks(init_end); __ticks_per_sec = init_end - init_start; ticks_initialized = 1; } } LiTL-litl-0.2/src/litl_timer.h000066400000000000000000000055111415666016500162410ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #ifndef LITL_TIMER_H_ #define LITL_TIMER_H_ /** * \file litl_timer.h * \brief litl_timer Provides a set of functions for measuring time * * \authors * Developers are : \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include "litl_types.h" /** * \defgroup litl_timer LiTL Timing Methods */ /** * \defgroup litl_timer_init Initialization Functions * \ingroup litl_timer */ /** * \defgroup litl_timer_measure Pre-Defined Timing Methods * \ingroup litl_timer */ /** * \ingroup litl_timer_init * \brief A callback function that returns the current time in ns. It can be * either a pointer to one of the timing functions provided by LiTL or a * user-defined function */ typedef litl_time_t (*litl_timing_method_t)(); /** * \ingroup litl_timer_measure * \brief Calls the selected timing method and get the current time in ns */ extern litl_timing_method_t litl_get_time; /** * \ingroup litl_timer_init * \brief Initializes the timing mechanism */ void litl_time_initialize(); /** * \ingroup litl_timer_init * \brief Selects the timing function to use * \param callback A name of timing function * \return Returns -1 if an error occurs. Otherwise, returns 0 */ int litl_set_timing_method(litl_timing_method_t callback); // Pre-defined timing methods: /** * \ingroup litl_timer_measure * \brief Uses clock_gettime(CLOCK_MONOTONIC_RAW) * \return Returns time that is similar to CLOCK_MONOTONIC, but provides access * to a raw hardware-based time */ litl_time_t litl_get_time_monotonic_raw(); /** * \ingroup litl_timer_measure * \brief Uses clock_gettime(CLOCK_MONOTONIC) * \return Returns the monotonic time since some unspecified starting point */ litl_time_t litl_get_time_monotonic(); /** * \ingroup litl_timer_measure * \brief Uses clock_gettime(CLOCK_REALTIME) * \return Returns the real (wall-clock) time */ litl_time_t litl_get_time_realtime(); /** * \ingroup litl_timer_measure * \brief Uses clock_gettime(CLOCK_PROCESS_CPUTIME) * \return Returns the high-resolution per-process time from the CPU */ litl_time_t litl_get_time_process_cputime(); /** * \ingroup litl_timer_measure * \brief Uses clock_gettime(CLOCK_THREAD_CPUTIME) * \return Returns the thread-specific CPU-time */ litl_time_t litl_get_time_thread_cputime(); /** * \ingroup litl_timer_measure * \brief Uses CPU-specific register (for instance, rdtsc for X86* processors) * \return Returns the measured time in clock cycles */ litl_time_t litl_get_time_ticks(); /** * \ingroup litl_timer_measure * \brief Ultra-fast measurement function * \return Always returns 0 */ litl_time_t litl_get_time_none(); #endif /* LITL_TIMER_H_ */ LiTL-litl-0.2/src/litl_tools.c000066400000000000000000000033531415666016500162560ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #include #include #include #include "litl_tools.h" #include "litl_write.h" /* * Returns the size in bytes of a REGULAR event depending on * the number of arguments */ litl_size_t __litl_get_reg_event_size(litl_data_t nb_params) { return LITL_BASE_SIZE + (nb_params * sizeof(litl_param_t)) + sizeof(litl_data_t); } litl_size_t __litl_get_event_size(litl_type_t type, int param_size) { switch (type) { case LITL_TYPE_REGULAR: return LITL_BASE_SIZE + (param_size * sizeof(litl_param_t)) + sizeof(litl_data_t); case LITL_TYPE_RAW: return LITL_BASE_SIZE + param_size + sizeof(((litl_t*)0)->parameters.raw.size); case LITL_TYPE_PACKED: return LITL_BASE_SIZE + param_size + sizeof(((litl_t*)0)->parameters.packed.size); case LITL_TYPE_OFFSET: return LITL_BASE_SIZE + param_size + sizeof(((litl_t*)0)->parameters.offset.nb_params); default: fprintf(stderr, "Unknown event type %d!\n", type); abort(); } return 0; } /* * Returns the size in bytes of an event of any type */ litl_size_t __litl_get_gen_event_size(litl_t *p_evt) { switch (p_evt->type) { case LITL_TYPE_REGULAR: return __litl_get_event_size(p_evt->type, p_evt->parameters.regular.nb_params); case LITL_TYPE_RAW: return __litl_get_event_size(p_evt->type, p_evt->parameters.raw.size); case LITL_TYPE_PACKED: return __litl_get_event_size(p_evt->type, p_evt->parameters.packed.size); case LITL_TYPE_OFFSET: return __litl_get_event_size(p_evt->type, p_evt->parameters.offset.nb_params); default: fprintf(stderr, "Unknown event type %d!\n", p_evt->type); abort(); } return 0; } LiTL-litl-0.2/src/litl_tools.h000066400000000000000000000026541415666016500162660ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #ifndef LITL_TOOLS_H_ #define LITL_TOOLS_H_ /** * \file litl_tools.h * \brief litl_tools Provides a set of auxiliary functions * * \authors * Developers are : \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include #include "litl_types.h" /** * \defgroup litl_tools LiTL Auxiliary Functions */ /** * \ingroup litl_tools * \brief Returns the size of a regular event (in Bytes) depending on the number * of its parameters * \param nb_params A number of event's parameters * \return A size of a regular event */ litl_size_t __litl_get_reg_event_size(litl_data_t nb_params); /** * \ingroup litl_tools * \brief Returns the size of an event (in Bytes) depending on the number or size * of its parameters * \param type The type of event * \param nb_params The number or size of parameters * \return A size of a regular event */ litl_size_t __litl_get_event_size(litl_type_t type, int param_size); /** * \ingroup litl_tools * \brief Returns the size of a general event (in Bytes) depending on its type * and the number of its parameters * \param p_evt A pointer to an event * \return A size of a given event */ litl_size_t __litl_get_gen_event_size(litl_t *p_evt); #endif /* LITL_TOOLS_H_ */ LiTL-litl-0.2/src/litl_types.h000066400000000000000000000342761415666016500162770ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file litl_types.h * \brief litl_types Provides a set of data structures for recording and * reading events as well as merging and splitting trace files * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #ifndef LITL_TYPES_H_ #define LITL_TYPES_H_ #include "litl_config.h" /** * \defgroup litl_types LiTL Data Types and Defined Variables */ /** * \defgroup litl_types_general General Data Types and Defined Variables * \ingroup litl_types */ /** * \defgroup litl_types_write Data Types for Recording Events * \ingroup litl_types */ /** * \defgroup litl_types_read Data Types for Reading Events * \ingroup litl_types */ /** * \defgroup litl_types_merge Data Types for Merging Traces * \ingroup litl_types */ /** * \defgroup litl_types_split Data Types for Splitting Archives of Traces * \ingroup litl_types */ #include #include #if USE_GETTID #include #include // For SYS_xxx definitions #else #include #endif // current thread id #if USE_GETTID /** * \ingroup litl_types_general * \brief A current thread ID */ #define CUR_TID syscall(SYS_gettid) #else /** * \ingroup litl_types_general * \brief A current thread ID */ #define CUR_TID pthread_self() #endif #if HAVE_32BIT /** * \ingroup litl_types_general * \brief A data type for storing thread IDs */ typedef uint32_t litl_tid_t; /** * \ingroup litl_types_general * \brief A data type for storing time stamps */ typedef uint32_t litl_time_t; /** * \ingroup litl_types_general * \brief A data type for storing traces sizes */ typedef uint32_t litl_trace_size_t; /** * \ingroup litl_types_general * \brief A data type for the non-optimized storage of parameters */ typedef uint32_t litl_param_t; /** * \ingroup litl_types_general * \brief A data type for storing offsets */ typedef uint32_t litl_offset_t; #else /* HAVE_32BIT */ /** * \ingroup litl_types_general * \brief A data type for storing thread IDs */ typedef uint64_t litl_tid_t; /** * \ingroup litl_types_general * \brief A data type for storing time stamps */ typedef uint64_t litl_time_t; /** * \ingroup litl_types_general * \brief A data type for storing traces sizes */ typedef uint64_t litl_trace_size_t; /** * \ingroup litl_types_general * \brief A data type for the non-optimized storage of parameters */ typedef uint64_t litl_param_t; /** * \ingroup litl_types_general * \brief A data type for storing offsets */ typedef uint64_t litl_offset_t; #endif /* HAVE_32BIT */ /** * \ingroup litl_types_general * \brief A data type for storing sets of events */ typedef uint8_t* litl_buffer_t; // TODO: there is a possibility of using uint16_t, however then the alignment // would collapse /** * \ingroup litl_types_general * \brief A data type for storing events codes */ typedef uint32_t litl_code_t; /** * \ingroup litl_types_general * \brief An auxiliary data type for storing data */ typedef uint32_t litl_size_t; /** * \ingroup litl_types_general * \brief An auxiliary data type for the optimized storage of data */ typedef uint16_t litl_med_size_t; /** * \ingroup litl_types_general * \brief A data type for the optimized storage of parameters */ typedef uint8_t litl_data_t; /** * \ingroup litl_types_general * \brief Defines the code of an event of type offset */ #define LITL_OFFSET_CODE 13 /** * \ingroup litl_types_general * \brief Defines the maximum number of parameters */ #define LITL_MAX_PARAMS 10 /** * \ingroup litl_types_general * \brief Defines the "maximum" size of raw data */ #define LITL_MAX_DATA (LITL_MAX_PARAMS * sizeof(litl_param_t)) /** * \ingroup litl_types_general * \brief The enumeration of event types */ typedef enum { LITL_TYPE_REGULAR /**< Regular */, LITL_TYPE_RAW /**< Raw */, LITL_TYPE_PACKED /**< Packed */, LITL_TYPE_OFFSET /**< Offset */ }__attribute__((packed)) litl_type_t; /** * \struct litl_t * \ingroup litl_types_general * \brief A general structure of LiTL event type */ typedef struct { litl_time_t time; /**< The time of the measurement */ litl_code_t code; /**< An event code */ litl_type_t type; /**< An event type */ /** * \union parameters * \brief Event parameters */ union { /** * \struct regular * \brief A regular event */ struct { litl_data_t nb_params; /**< A number of arguments */ litl_param_t param[LITL_MAX_PARAMS]; /**< An array of arguments of lengths from 0 to 10 */ }__attribute__((packed)) regular; /** * \struct raw * \brief A raw event */ struct { litl_size_t size; /**< A size of data (in Bytes) */ litl_data_t data[LITL_MAX_DATA]; /**< A raw data */ }__attribute__((packed)) raw; /** * \struct packed * \brief A packed event */ struct { litl_size_t size; /**< A size of data (in Bytes) */ litl_data_t param[LITL_MAX_DATA]; /**< A data */ }__attribute__((packed)) packed; /** * \struct offset * \brief An offset event */ struct { litl_data_t nb_params; /**< A number of parameters (=1) */ litl_param_t offset; /**< An offset to the next chunk of events */ }__attribute__((packed)) offset; } parameters; }__attribute__((packed)) litl_t; /** * \ingroup litl_types_general * \brief Defines the maximum number of threads (pairs of tid and offset) stored * in one data * slot */ #define NBTHREADS 32 /** * \ingroup litl_types_general * \brief A general data structure that corresponds to the header of a trace * file */ typedef struct { litl_data_t litl_ver[8]; /**< Information regarding the version of LiTL */ litl_data_t sysinfo[128]; /**< Information regarding OS, Hardware, etc. */ litl_med_size_t nb_processes; /**< A number of processes in the trace file */ }__attribute__((packed)) litl_general_header_t; /** * \ingroup litl_types_general * \brief A general data structure that corresponds to the header of a trace * file */ typedef struct { litl_data_t process_name[256]; /**< A name of the process */ litl_med_size_t nb_threads; /**< A total number of threads */ litl_med_size_t header_nb_threads; /**< A number of threads, which info is stored in the header */ litl_size_t buffer_size; /**< A size of buffer */ litl_trace_size_t trace_size; /**< A trace size */ litl_offset_t offset; /**< An offset to the process-specific threads pairs and their events */ }__attribute__((packed)) litl_process_header_t; /** * \ingroup litl_types_general * \brief A data structure for pairs (tid, offset) stored in the trace header */ typedef struct { litl_tid_t tid; /**< A thread ID */ litl_offset_t offset; /**< An offset to the chunk of events */ } litl_thread_pair_t; /** * \ingroup litl_types_general * \brief A data structure for triples (nb_processes, position, offset) */ typedef struct { litl_med_size_t nb_processes; /**< A number of processes */ litl_offset_t position; /**< A position of the offset within the archive */ litl_offset_t offset; /**< An offset to process-specific data */ } litl_trace_triples_t; /** * \ingroup litl_types_write * \brief Thread-specific buffer */ typedef struct { litl_buffer_t buffer_ptr; /**< A pointer to the beginning of the buffer */ litl_buffer_t buffer; /**< A pointer to the next free slot */ litl_tid_t tid; /**< An ID of the working thread */ litl_offset_t offset; /**< An offset to the next buffer in the trace file */ litl_data_t already_flushed; /**< Handles the situation when some threads start after the header was flushed, i.e. their tids and offsets were not included into the header*/ int initialized; } litl_write_buffer_t; /** * \ingroup litl_types_write * \brief A data structure for recording events */ typedef struct { int f_handle; /**< A file handler */ char* filename; /**< A file name */ litl_offset_t general_offset; /**< An offset from the beginning of the trace file to the next free slot */ litl_buffer_t header_ptr; /**< A pointer to the beginning of the header */ litl_buffer_t header; /**< A pointer to the next free slot in the header */ litl_size_t header_size; /**< A header size */ litl_size_t header_offset; /**< An offset from the beginning of the header to the next free slot */ litl_med_size_t header_nb_threads; /**< A number of threads in the header */ litl_data_t is_header_flushed; /**< Indicates whether the header with threads pairs has been flushed */ litl_med_size_t nb_threads; /**< A number of threads */ litl_med_size_t nb_slots; /**< A number of chunks with the information on threads (tid, offset); first chunk, which is in the header, does not count; each contains at most NBTHREADS threads */ litl_param_t threads_offset; /**< An offset to the next chunk of pairs (tid, offset) for a given thread */ litl_write_buffer_t **buffers; /**< An array of thread-specific buffers */ litl_size_t nb_allocated_buffers; /**< A number of thread-specific buffers that are allocated */ litl_size_t buffer_size; /**< A buffer size */ litl_data_t is_buffer_full; /**< Indicates whether the buffer is full */ pthread_once_t index_once; /**< Guarantees that the initialization function is called only once */ pthread_key_t index; /**< A private thread variable that holds its index */ pthread_mutex_t lock_litl_flush; /**< Handles write conflicts while using pthread */ pthread_mutex_t lock_buffer_init; /**< Handles race conditions while initializing threads pairs and buffers pointers */ litl_data_t is_litl_initialized; /**< Ensures that a performance analysis library does not start recording events before the initialization is finished */ volatile litl_data_t is_recording_paused; /**< Indicates whether LiTL stops recording events (1) for a while or not (0) */ litl_data_t allow_buffer_flush; /**< Indicates whether buffer flush is enabled (1) or not (0). In case the flushing is disabled, the recording of events is stopped. By default, it is activated */ litl_data_t allow_thread_safety; /**< Indicates whether LiTL uses thread-safety (1) or not (0). By default, it is activated */ litl_data_t allow_tid_recording; /**< Indicates whether LiTL records tid (1) or not (0). By default, it is activated */ } litl_write_trace_t; /** * \ingroup litl_types_read * \brief A data structure for reading one event */ typedef struct { litl_tid_t tid; /**< A thread ID */ litl_t *event; /**< A pointer to the read event */ } litl_read_event_t; /** * \ingroup litl_types_read * \brief A data structure for reading thread-specific events */ typedef struct { litl_thread_pair_t* thread_pair; /**< A thread pair (tid, offset) */ litl_buffer_t buffer_ptr; /**< A pointer to the beginning of the buffer */ litl_buffer_t buffer; /**< A pointer to the current position in the buffer */ litl_offset_t offset; /**< An offset from the beginning of the buffer */ litl_offset_t tracker; /**< An indicator of the end of the buffer, which equals to offset + buffer_size */ litl_read_event_t cur_event; /**< The current event */ } litl_read_thread_t; /** * \ingroup litl_types_read * \brief A data structure for reading process-specific events */ typedef struct { litl_process_header_t* header; /**< A pointer to the process header */ litl_buffer_t header_buffer_ptr; /**< A pointer to the beginning of the header buffer */ litl_buffer_t header_buffer; /**< A pointer to the current position within the header buffer */ litl_med_size_t nb_threads; /**< A number of threads */ litl_read_thread_t **threads; /**< An array of threads */ int cur_index; /**< An index of the current thread */ int is_initialized; /**< Indicates that the process was initialized */ } litl_read_process_t; /** * \ingroup litl_types_read * \brief A data structure for reading events from both regular trace files and * archives of traces */ typedef struct { int f_handle; /**< A file handler */ litl_general_header_t* header; /**< A pointer to the trace header */ litl_buffer_t header_buffer_ptr; /**< A pointer to the beginning of the header buffer */ litl_buffer_t header_buffer; /**< A pointer to the current position in the header buffer */ litl_med_size_t nb_processes; /**< A number of processes */ litl_read_process_t **processes; /**< An array of processes */ } litl_read_trace_t; /** * \ingroup litl_types_merge * \brief A data structure for merging trace files into an archive of traces */ typedef struct { int f_handle; /**< A file handler */ char* filename; /**< A file name */ litl_med_size_t nb_traces; /**< A number of traces */ char** traces_names; /**< An array of traces names */ litl_buffer_t buffer_ptr; /**< A pointer to the beginning of the buffer */ litl_buffer_t buffer; /**< A pointer to the current position in the buffer */ litl_size_t buffer_size; /**< A buffer size */ litl_offset_t general_offset; /**< An offset from the beginning of the trace file till the current position */ } litl_trace_merge_t; /** * \ingroup litl_types_split * \brief A data structure for splitting an archive of traces */ typedef struct { int f_handle; /**< A file handler */ litl_buffer_t header_buffer_ptr; /**< A pointer to the beginning of the header buffer */ litl_buffer_t header_buffer; /**< A pointer to the current position within the header buffer */ litl_general_header_t* trace_header; /**< A pointer to a trace header */ litl_process_header_t* process_header; /**< A pointer to a process header */ litl_med_size_t nb_processes; /**< A number of processes */ litl_buffer_t buffer; /**< A pointer to the buffer */ litl_size_t buffer_size; /**< A buffer size */ } litl_trace_split_t; /* * Defining formats for printing data */ #define PRTIu32 "u" #define PRTIx32 "x" #if HAVE_32BIT #define PRTIu64 "u" #define PRTIx64 "x" #else #define PRTIu64 "lu" #define PRTIx64 "lx" #endif /* HAVE_32BIT */ /* * For internal use only. * Computes the offset of MEMBER in structure TYPE */ #define __litl_offset_of(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) /* * For internal use only. * Computes the offset of the first parameter in an event */ #define LITL_BASE_SIZE __litl_offset_of(litl_t, parameters) #endif /* LITL_TYPES_H_ */ LiTL-litl-0.2/src/litl_write.c000066400000000000000000000705331415666016500162540ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "litl_timer.h" #include "litl_tools.h" #include "litl_write.h" #include "litl_config.h" /* * Adds a header to the trace file with the information regarding: * - OS * - Processor type * - Version of LiTL */ static void __litl_write_add_trace_header(litl_write_trace_t* trace) { struct utsname uts; // allocate memory for the trace header trace->header_ptr = (litl_buffer_t) malloc(trace->header_size); if (!trace->header_ptr) { perror("Could not allocate memory for the trace header!"); exit(EXIT_FAILURE); } trace->header = trace->header_ptr; memset(trace->header_ptr, 0, trace->header_size); if (uname(&uts) < 0) perror("Could not use uname()!"); // add a general header // version of LiTL sprintf((char*) ((litl_general_header_t *) trace->header)->litl_ver, "%s", VERSION); // system information sprintf((char*) ((litl_general_header_t *) trace->header)->sysinfo, "%s %s %s %s %s", uts.sysname, uts.nodename, uts.release, uts.version, uts.machine); // a number of processes ((litl_general_header_t *) trace->header)->nb_processes = 1; // move pointer trace->header += sizeof(litl_general_header_t); // add a process-specific header // by default one trace file contains events only of one process char* filename = strrchr(trace->filename, '/'); filename++; sprintf((char*) ((litl_process_header_t *) trace->header)->process_name, "%s", filename); ((litl_process_header_t *) trace->header)->nb_threads = trace->nb_threads; ((litl_process_header_t *) trace->header)->header_nb_threads = trace->nb_threads; ((litl_process_header_t *) trace->header)->buffer_size = trace->buffer_size; ((litl_process_header_t *) trace->header)->trace_size = 0; ((litl_process_header_t *) trace->header)->offset = sizeof(litl_general_header_t) + sizeof(litl_process_header_t); // header_size stores the position of nb_threads in the trace file trace->header_size = sizeof(litl_general_header_t) + 256 * sizeof(litl_data_t); // move pointer trace->header += sizeof(litl_process_header_t); } /* * Initializes the trace buffer */ litl_write_trace_t* litl_write_init_trace(const litl_size_t buf_size) { litl_med_size_t i; litl_write_trace_t* trace; trace = (litl_write_trace_t*) malloc(sizeof(litl_write_trace_t)); if (!trace) { perror("Could not allocate memory for the trace!"); exit(EXIT_FAILURE); } // set variables trace->filename = NULL; trace->general_offset = 0; trace->is_header_flushed = 0; // set the buffer size using the environment variable. // If the variable is not specified, use the provided value char* str = getenv("LITL_BUFFER_SIZE"); if (str != NULL ) trace->buffer_size = atoi(str); else trace->buffer_size = buf_size; trace->is_buffer_full = 0; trace->nb_allocated_buffers = 256; trace->buffers = malloc( sizeof(litl_write_buffer_t*) * trace->nb_allocated_buffers); if (!trace->buffers) { perror("Could not allocate memory for the threads!"); exit(EXIT_FAILURE); } for (i = 0; i < trace->nb_allocated_buffers; i++) { // initialize the array already_flushed trace->buffers[i] = malloc(sizeof(litl_write_buffer_t)); if (!trace->buffers[i]) { perror("Could not allocate memory for a thread\n"); exit(EXIT_FAILURE); } trace->buffers[i]->already_flushed = 0; // initialize tids by zeros; this is needed for __is_tid and __find_slot trace->buffers[i]->tid = 0; } trace->nb_threads = 0; // initialize the timing mechanism litl_time_initialize(); assert(pthread_key_create(&trace->index, NULL ) == 0); // set trace->allow_buffer_flush using the environment variable. // By default the buffer flushing is disabled litl_write_buffer_flush_off(trace); str = getenv("LITL_BUFFER_FLUSH"); if (str) { if(strcmp(str, "0") == 0) litl_write_buffer_flush_off(trace); else litl_write_buffer_flush_on(trace); } // set trace->allow_thread_safety using the environment variable. // By default thread safety is enabled litl_write_thread_safety_on(trace); str = getenv("LITL_THREAD_SAFETY"); if (str && (strcmp(str, "0") == 0)) litl_write_thread_safety_off(trace); if (trace->allow_thread_safety) pthread_mutex_init(&trace->lock_litl_flush, NULL ); pthread_mutex_init(&trace->lock_buffer_init, NULL ); // set trace->allow_tid_recording using the environment variable. // By default tid recording is enabled litl_write_tid_recording_on(trace); str = getenv("LITL_TID_RECORDING"); if (str && (strcmp(str, "0") == 0)) litl_write_tid_recording_off(trace); trace->is_recording_paused = 0; trace->is_litl_initialized = 1; return trace; } /* * Computes the size of data in the trace header */ static litl_size_t __litl_write_get_header_size(litl_write_trace_t* trace) { return (trace->header - trace->header_ptr); } /* * Computes the size of data in buffer */ static litl_size_t __litl_write_get_buffer_size(litl_write_trace_t* trace, litl_med_size_t pos) { return (trace->buffers[pos]->buffer - trace->buffers[pos]->buffer_ptr); } /* * Activates buffer flush */ void litl_write_buffer_flush_on(litl_write_trace_t* trace) { trace->allow_buffer_flush = 1; } /* * Deactivates buffer flush. By default, it is activated */ void litl_write_buffer_flush_off(litl_write_trace_t* trace) { trace->allow_buffer_flush = 0; } /* * Activate thread safety. By default it is deactivated */ void litl_write_thread_safety_on(litl_write_trace_t* trace) { trace->allow_thread_safety = 1; } /* * Deactivates thread safety */ void litl_write_thread_safety_off(litl_write_trace_t* trace) { trace->allow_thread_safety = 0; } /* * Activates recording tid. By default it is deactivated */ void litl_write_tid_recording_on(litl_write_trace_t* trace) { trace->allow_tid_recording = 1; } /* * Deactivates recording tid */ void litl_write_tid_recording_off(litl_write_trace_t* trace) { trace->allow_tid_recording = 0; } /* * Pauses the event recording */ void litl_write_pause_recording(litl_write_trace_t* trace) { if (trace) trace->is_recording_paused = 1; } /* * Resumes the event recording */ void litl_write_resume_recording(litl_write_trace_t* trace) { if (trace) trace->is_recording_paused = 0; } /* * Sets a new name for the trace file */ void litl_write_set_filename(litl_write_trace_t* trace, char* filename) { if (trace->filename) { if (trace->is_header_flushed) fprintf( stderr, "Warning: changing the trace file name to %s after some events have been saved in file %s\n", filename, trace->filename); free(trace->filename); } // check whether the file name was set. If no, set it by default trace name. if (filename == NULL ) sprintf(filename, "/tmp/%s_%s", getenv("USER"), "litl_log_1"); if (asprintf(&trace->filename, "%s", filename) == -1) { perror("Error: Cannot set the filename for recording events!\n"); exit(EXIT_FAILURE); } } /* * Records an event with offset only */ static void __litl_write_probe_offset(litl_write_trace_t* trace, litl_med_size_t index) { if (!trace->is_litl_initialized || trace->is_recording_paused) return; litl_t* cur_ptr = (litl_t *) trace->buffers[index]->buffer; cur_ptr->time = 0; cur_ptr->code = LITL_OFFSET_CODE; cur_ptr->type = LITL_TYPE_REGULAR; cur_ptr->parameters.offset.nb_params = 1; cur_ptr->parameters.offset.offset = 0; trace->buffers[index]->buffer += __litl_get_gen_event_size(cur_ptr); } /* Open the trace file. If the file already exists, delete it first */ static void __litl_open_new_file(litl_write_trace_t* trace) { /* if file exist. delete it first */ if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) { if(errno == EEXIST) { /* file already exist. Delete it and open it */ if(unlink(trace->filename) < 0 ){ perror("Cannot delete trace file"); exit(EXIT_FAILURE); } if ((trace->f_handle = open(trace->filename, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) { perror("Cannot open trace file"); exit(EXIT_FAILURE); } } else { fprintf(stderr, "Cannot open %s\n", trace->filename); exit(EXIT_FAILURE); } } } /* * Write the header on the disk */ static void __litl_write_update_header(litl_write_trace_t* trace) { // write the trace header to the trace file assert(trace->f_handle >= 0); lseek(trace->f_handle, 0, SEEK_SET); if (write(trace->f_handle, trace->header_ptr, __litl_write_get_header_size(trace)) == -1) { perror( "Flushing the buffer. Could not write measured data to the trace file!"); exit(EXIT_FAILURE); } } /* * Update the header and flush it to disk */ static void __litl_write_flush_header(litl_write_trace_t* trace) { if (!trace->is_header_flushed) { // open the trace file __litl_open_new_file(trace); // add a header to the trace file trace->header_size = sizeof(litl_general_header_t) + sizeof(litl_process_header_t) + (trace->nb_threads + 1) * sizeof(litl_thread_pair_t); __litl_write_add_trace_header(trace); // add information about each working thread: (tid, offset) litl_med_size_t i; for (i = 0; i < trace->nb_threads; i++) { ((litl_thread_pair_t *) trace->header)->tid = trace->buffers[i]->tid; ((litl_thread_pair_t *) trace->header)->offset = 0; trace->header += sizeof(litl_thread_pair_t); // save the position of offset inside the trace file trace->buffers[i]->offset = __litl_write_get_header_size(trace) - sizeof(litl_offset_t); trace->buffers[i]->already_flushed = 1; } // offset indicates the position of offset to the next slot of // pairs (tid, offset) within the trace file trace->header_offset = __litl_write_get_header_size(trace); // specify the last slot of pairs (offset == 0) litl_thread_pair_t *thread_pair = (litl_thread_pair_t *) trace->header; trace->header += sizeof(litl_thread_pair_t); thread_pair->tid = 0; thread_pair->offset = 0; // write the trace header to the trace file __litl_write_update_header(trace); trace->general_offset = __litl_write_get_header_size(trace); trace->header_nb_threads = trace->nb_threads; trace->threads_offset = 0; trace->nb_slots = 0; trace->is_header_flushed = 1; } } /* * Write the thread-specific header to disk */ static void __litl_write_flush_thread_header(litl_write_trace_t* trace, litl_med_size_t index, litl_offset_t header_size) { litl_offset_t offset; int res; // when more buffers to store threads information is required if (trace->nb_threads > (trace->header_nb_threads + NBTHREADS * trace->nb_slots)) { // updated the offset from the previous slot lseek(trace->f_handle, trace->header_offset + sizeof(litl_tid_t), SEEK_SET); offset = trace->general_offset - header_size; res = write(trace->f_handle, &offset, sizeof(litl_offset_t)); assert(res>=0); // reserve a new slot for pairs (tid, offset) trace->header_offset = trace->general_offset; trace->threads_offset = trace->header_offset; trace->general_offset += (NBTHREADS + 1) * sizeof(litl_thread_pair_t); trace->nb_slots++; } // add a new pair (tid, offset) lseek(trace->f_handle, trace->header_offset, SEEK_SET); res = write(trace->f_handle, &trace->buffers[index]->tid, sizeof(litl_tid_t)); assert(res >= 0); offset = trace->general_offset - header_size; res = write(trace->f_handle, &offset, sizeof(litl_offset_t)); assert(res >= 0); // add an indicator to specify the last slot of pairs (offset == 0) // TODO: how to optimize this and write only once at the end of the slot offset = 0; res = write(trace->f_handle, &offset, sizeof(litl_tid_t)); assert(res >= 0); res = write(trace->f_handle, &offset, sizeof(litl_offset_t)); assert(res >= 0); trace->header_offset += sizeof(litl_thread_pair_t); trace->buffers[index]->already_flushed = 1; // updated the number of threads // TODO: perform update only once 'cause there is duplication lseek(trace->f_handle, trace->header_size, SEEK_SET); res = write(trace->f_handle, &trace->nb_threads, sizeof(litl_med_size_t)); assert(res >= 0); } /* * Update the thread-specific header and write it to disk */ static void __litl_write_update_thread_header(litl_write_trace_t* trace, litl_med_size_t index, litl_offset_t header_size) { // update the previous offset of the current thread, // updating the location in the file lseek(trace->f_handle, trace->buffers[index]->offset, SEEK_SET); litl_offset_t offset = trace->general_offset - header_size; int res = write(trace->f_handle, &offset, sizeof(litl_offset_t)); assert(res >= 0); } /* * Writes the recorded events from the buffer to the trace file */ static void __litl_write_flush_buffer(litl_write_trace_t* trace, litl_med_size_t index) { int res __attribute__ ((__unused__)); litl_offset_t header_size; if (!trace->is_litl_initialized) return; if (trace->allow_thread_safety) pthread_mutex_lock(&trace->lock_litl_flush); if (!trace->is_header_flushed) { /* flush the header to disk */ __litl_write_flush_header(trace); } header_size = sizeof(litl_general_header_t) + sizeof(litl_process_header_t); // handle the situation when some threads start after the header was flushed if (!trace->buffers[index]->already_flushed) { __litl_write_flush_thread_header(trace, index, header_size); } else { __litl_write_update_thread_header(trace, index, header_size); } // add an event with offset __litl_write_probe_offset(trace, index); lseek(trace->f_handle, trace->general_offset, SEEK_SET); if (write(trace->f_handle, trace->buffers[index]->buffer_ptr, __litl_write_get_buffer_size(trace, index)) == -1) { perror( "Flushing the buffer. Could not write measured data to the trace file!"); exit(EXIT_FAILURE); } // update the general_offset trace->general_offset += __litl_write_get_buffer_size(trace, index); // update the current offset of the thread trace->buffers[index]->offset = trace->general_offset - sizeof(litl_offset_t); if (trace->allow_thread_safety) pthread_mutex_unlock(&trace->lock_litl_flush); trace->buffers[index]->buffer = trace->buffers[index]->buffer_ptr; } /* * Checks whether the trace buffer was allocated. If no, then allocate * the buffer and, for otherwise too, returns the position of * the thread buffer in the array buffer_ptr/buffer. */ static void __litl_write_allocate_buffer(litl_write_trace_t* trace) { litl_med_size_t* pos; // thread safe region pthread_mutex_lock(&trace->lock_buffer_init); pos = malloc(sizeof(litl_med_size_t)); *pos = trace->nb_threads; int thread_id = *pos; pthread_setspecific(trace->index, pos); trace->nb_threads++; if (*pos >= trace->nb_allocated_buffers) { // We need to allocate a bigger array of buffers void* ptr = realloc( trace->buffers, trace->nb_allocated_buffers * 2 * sizeof(litl_write_buffer_t*)); if (!ptr) { perror("LiTL failed to reallocate memory for threads!\n"); exit(EXIT_FAILURE); } trace->buffers = ptr; unsigned i; for (i = trace->nb_allocated_buffers; i < 2 * trace->nb_allocated_buffers; i++) { trace->buffers[i] = malloc(sizeof(litl_write_buffer_t)); if (!trace->buffers[i]) { perror("Could not allocate memory for a thread\n!"); exit(EXIT_FAILURE); } trace->buffers[i]->already_flushed = 0; trace->buffers[i]->initialized = 0; } trace->nb_allocated_buffers *= 2; } trace->buffers[thread_id]->tid = CUR_TID; trace->buffers[thread_id]->already_flushed = 0; pthread_mutex_unlock(&trace->lock_buffer_init); /* use mmap instead of malloc so that we can use the MAP_POPULATE option that makes sure the page table is populated. This way, the page faults caused by litl are sensibly reduced. */ #define USE_MMAP #ifdef USE_MMAP size_t length = trace->buffer_size + __litl_get_reg_event_size(LITL_MAX_PARAMS) + __litl_get_reg_event_size(1); int mmap_flags = MAP_SHARED|MAP_ANONYMOUS; #ifdef MAP_POPULATE /* make sure the pages are in the page table. This should reduce page faults when recording events */ mmap_flags |= MAP_POPULATE; #endif trace->buffers[thread_id]->buffer_ptr = mmap(NULL, length, PROT_READ|PROT_WRITE, mmap_flags, -1, 0); if(trace->buffers[thread_id]->buffer_ptr == MAP_FAILED) { perror("mmap"); } #ifdef MAP_POPULATE /* touch the first pages */ if(length> 1024*1024) length=1024*1024; #endif /* if MAP_POPULATE is not available, touch the whole buffer to avoid future page faults */ memset(trace->buffers[thread_id]->buffer_ptr, 0, length); #else /* USE_MMAP */ size_t length = trace->buffer_size + __litl_get_reg_event_size(LITL_MAX_PARAMS) + __litl_get_reg_event_size(1); trace->buffers[thread_id]->buffer_ptr = malloc(length); #endif /* USE_MMAP */ if (!trace->buffers[thread_id]->buffer_ptr) { perror("Could not allocate memory buffer for the thread\n!"); exit(EXIT_FAILURE); } // touch the memory so that it is allocated for real (otherwise, this may // cause performance issues on NUMA machines) memset(trace->buffers[thread_id]->buffer_ptr, 1, 1); trace->buffers[thread_id]->buffer = trace->buffers[thread_id]->buffer_ptr; trace->buffers[thread_id]->initialized = 1; } /* * For internal use only. * Allocates an event */ litl_t* __litl_write_get_event(litl_write_trace_t* trace, litl_type_t type, litl_code_t code, int param_size) { litl_med_size_t index = 0; litl_t*retval = NULL; litl_size_t event_size = __litl_get_event_size(type, param_size); if (trace && trace->is_litl_initialized && !trace->is_recording_paused && !trace->is_buffer_full) { // find the thread index litl_med_size_t *p_index = pthread_getspecific(trace->index); if (!p_index) { __litl_write_allocate_buffer(trace); p_index = pthread_getspecific(trace->index); if(!p_index) return NULL; } index = *(litl_med_size_t *) p_index; if(trace->buffers[index]->initialized == 0) return NULL; litl_write_buffer_t *p_buffer = trace->buffers[index]; // is there enough space in the buffer? litl_size_t used_memory= __litl_write_get_buffer_size(trace, index); if (used_memory+event_size < trace->buffer_size) { // there is enough space for this event litl_t* cur_ptr = (litl_t*) p_buffer->buffer; // fill the event cur_ptr->time = litl_get_time(); cur_ptr->code = code; cur_ptr->type = type; switch (type) { case LITL_TYPE_REGULAR: cur_ptr->parameters.regular.nb_params = (param_size) / sizeof(litl_param_t); break; case LITL_TYPE_RAW: cur_ptr->parameters.raw.size = param_size; break; case LITL_TYPE_PACKED: cur_ptr->parameters.packed.size = param_size; break; case LITL_TYPE_OFFSET: cur_ptr->parameters.offset.nb_params = param_size; break; default: fprintf(stderr, "Unknown event type %d\n", type); abort(); } p_buffer->buffer += __litl_get_gen_event_size(cur_ptr); retval = cur_ptr; goto out; } else if (trace->allow_buffer_flush) { // not enough space. flush the buffer and retry __litl_write_flush_buffer(trace, index); retval = __litl_write_get_event(trace, type, code, param_size); goto out; } else { // not enough space, but flushing is disabled so just stop recording trace->is_buffer_full = 1; retval = NULL ; goto out; } } out: return retval; } /* Common function for recording a regular event. * This function fills all the fiels except for the parameters */ static litl_t* __litl_write_probe_reg_common(litl_write_trace_t* trace, litl_code_t code, unsigned nb_params) { litl_t*retval = __litl_write_get_event(trace, LITL_TYPE_REGULAR, code, nb_params); return retval; } /* * Records a regular event without any arguments */ litl_t* litl_write_probe_reg_0(litl_write_trace_t* trace, litl_code_t code) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 0); return cur_ptr; } /* * Records a regular event with one argument */ litl_t* litl_write_probe_reg_1(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 1); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; } return cur_ptr; } /* * Records a regular event with two arguments */ litl_t* litl_write_probe_reg_2(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 2); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; } return cur_ptr; } /* * Records a regular event with three arguments */ litl_t* litl_write_probe_reg_3(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 3); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; } return cur_ptr; } /* * Records a regular event with four arguments */ litl_t* litl_write_probe_reg_4(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 4); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; } return cur_ptr; } /* * Records a regular event with five arguments */ litl_t* litl_write_probe_reg_5(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 5); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; } return cur_ptr; } /* * Records a regular event with six arguments */ litl_t* litl_write_probe_reg_6(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 6); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; cur_ptr->parameters.regular.param[5] = param6; } return cur_ptr; } /* * Records a regular event with seven arguments */ litl_t* litl_write_probe_reg_7(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 7); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; cur_ptr->parameters.regular.param[5] = param6; cur_ptr->parameters.regular.param[6] = param7; } return cur_ptr; } /* * Records a regular event with eight arguments */ litl_t* litl_write_probe_reg_8(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 8); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; cur_ptr->parameters.regular.param[5] = param6; cur_ptr->parameters.regular.param[6] = param7; cur_ptr->parameters.regular.param[7] = param8; } return cur_ptr; } /* * Records a regular event with nine arguments */ litl_t* litl_write_probe_reg_9(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 9); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; cur_ptr->parameters.regular.param[5] = param6; cur_ptr->parameters.regular.param[6] = param7; cur_ptr->parameters.regular.param[7] = param8; cur_ptr->parameters.regular.param[8] = param9; } return cur_ptr; } /* * Records a regular event with ten arguments */ litl_t* litl_write_probe_reg_10(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9, litl_param_t param10) { litl_t *cur_ptr = __litl_write_probe_reg_common(trace, code, 10); if(cur_ptr) { cur_ptr->parameters.regular.param[0] = param1; cur_ptr->parameters.regular.param[1] = param2; cur_ptr->parameters.regular.param[2] = param3; cur_ptr->parameters.regular.param[3] = param4; cur_ptr->parameters.regular.param[4] = param5; cur_ptr->parameters.regular.param[5] = param6; cur_ptr->parameters.regular.param[6] = param7; cur_ptr->parameters.regular.param[7] = param8; cur_ptr->parameters.regular.param[8] = param9; cur_ptr->parameters.regular.param[9] = param10; } return cur_ptr; } /* * Records an event in a raw state, where the size is #args in the void* array. * That helps to discover places where the application has crashed */ litl_t* litl_write_probe_raw(litl_write_trace_t* trace, litl_code_t code, litl_size_t size, litl_data_t data[]) { litl_t* retval = __litl_write_get_event(trace, LITL_TYPE_RAW, code, size+1); if(retval) { litl_size_t i; for (i = 0; i < size; i++) { retval->parameters.raw.data[i] = data[i]; } retval->parameters.raw.data[size]='\0'; } return retval; } /* * This function finalizes the trace */ void litl_write_finalize_trace(litl_write_trace_t* trace) { litl_med_size_t i; if(!trace) return; for (i = 0; i < trace->nb_threads; i++) { __litl_write_flush_buffer(trace, i); } close(trace->f_handle); trace->f_handle = -1; for (i = 0; i < trace->nb_allocated_buffers; i++) { if (trace->buffers[i]->tid != 0) { size_t length = trace->buffer_size + __litl_get_reg_event_size(LITL_MAX_PARAMS) + __litl_get_reg_event_size(1); #ifdef USE_MMAP int ret = munmap(trace->buffers[i]->buffer_ptr, length); assert(ret==0); #else free(trace->buffers[i]->buffer_ptr); #endif trace->buffers[i]->buffer_ptr = NULL; } else { break; } } if (trace->allow_thread_safety) { pthread_mutex_destroy(&trace->lock_litl_flush); } pthread_mutex_destroy(&trace->lock_buffer_init); free(trace->filename); trace->filename = NULL; trace->is_litl_initialized = 0; trace->is_header_flushed = 0; free(trace); } LiTL-litl-0.2/src/litl_write.h000066400000000000000000000612011415666016500162510ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file litl_write.h * \brief litl_write Provides a set of functions for recording events in a * trace file * * \authors * Developers are : \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #ifndef LITL_WRITE_H_ #define LITL_WRITE_H_ #include "litl_types.h" /** * \defgroup litl_write LiTL Writing Functions */ /** * \defgroup litl_write_init Initialization Functions * \ingroup litl_write */ /** * \defgroup litl_write_reg Functions for Recording Regular Events * \ingroup litl_write */ /** * \defgroup litl_write_raw Functions for Recording Raw Events * \ingroup litl_write */ /** * \defgroup litl_write_pack Functions for Recording Packed Events * \ingroup litl_write */ /** * \ingroup litl_write_init * \brief Initializes the trace buffer * \param buf_size A buffer size (in Byte) * \return A pointer to the event recording object. * NULL in case of failure */ litl_write_trace_t* litl_write_init_trace(const uint32_t buf_size); /** * \ingroup litl_write_init * \brief Enable buffer flush. By default, it is disabled * \param trace A pointer to the event recording object */ void litl_write_buffer_flush_on(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Disable buffer flush. * \param trace A pointer to the event recording object */ void litl_write_buffer_flush_off(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Enable thread safety * \param trace A pointer to the event recording object */ void litl_write_thread_safety_on(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Disable thread safety. By default, it is enabled * \param trace A pointer to the event recording object */ void litl_write_thread_safety_off(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Enable recording tid */ void litl_write_tid_recording_on(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Disable recording tid. By default, it is enabled * \param trace A pointer to the event recording object */ void litl_write_tid_recording_off(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Pauses the event recording * \param trace A pointer to the event recording object */ void litl_write_pause_recording(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Resumes the event recording * \param trace A pointer to the event recording object */ void litl_write_resume_recording(litl_write_trace_t* trace); /** * \ingroup litl_write_init * \brief Sets a new name for the trace file * \param trace A pointer to the event recording object * \param filename A new file name */ void litl_write_set_filename(litl_write_trace_t* trace, char* filename); /*** Regular events ***/ /** * \ingroup litl_write_reg * \brief Records a regular event without parameters * \param trace A pointer to the event recording object * \param code An event code * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_0(litl_write_trace_t* trace, litl_code_t code); /** * \ingroup litl_write_reg * \brief Records a regular event with 1 parameter * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_1(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1); /** * \ingroup litl_write_reg * \brief Records a regular event with 2 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_2(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2); /** * \ingroup litl_write_reg * \brief Records a regular event with 3 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_3(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3); /** * \ingroup litl_write_reg * \brief Records a regular event with 4 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_4(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4); /** * \ingroup litl_write_reg * \brief Records a regular event with 5 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_5(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5); /** * \ingroup litl_write_reg * \brief Records a regular event with 6 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_6(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6); /** * \ingroup litl_write_reg * \brief Records a regular event with 7 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_7(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7); /** * \ingroup litl_write_reg * \brief Records a regular event with 8 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_8(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8); /** * \ingroup litl_write_reg * \brief Records a regular event with 9 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_9(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9); /** * \ingroup litl_write_reg * \brief Records a regular event with 10 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event * \param param10 10th parameter for this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_reg_10(litl_write_trace_t* trace, litl_code_t code, litl_param_t param1, litl_param_t param2, litl_param_t param3, litl_param_t param4, litl_param_t param5, litl_param_t param6, litl_param_t param7, litl_param_t param8, litl_param_t param9, litl_param_t param10); /*** Raw events ***/ /** * \ingroup litl_write_raw * \brief Records an event with data in a string format * \param trace A pointer to the event recording object * \param code An event code * \param size Size (in Bytes) of the data to store * \param data Data to store with this event * \return a pointer to the event that was recorded or NULL in case of error */ litl_t* litl_write_probe_raw(litl_write_trace_t* trace, litl_code_t code, litl_size_t size, litl_data_t data[]); /*** Internal-use macros ***/ /** * \ingroup litl_write_pack * \brief For internal use only. Allocates an event * \param trace A pointer to the event recording object * \param type An event type * \param code An event code * \param size Size of the event (in Bytes) * \return The allocated event or NULL in case of error */ litl_t* __litl_write_get_event(litl_write_trace_t* trace, litl_type_t type, litl_code_t code, int size); /** * \ingroup litl_write_pack * \brief For internal use only. Adds a parameter to a packed event * \param ptr A pointer to an event where the parameter should be stored * \param param A parameter to store */ #define __LITL_WRITE_ADD_ARG(ptr, param) do { \ typeof(param) _param = param; \ memcpy(ptr, &_param, sizeof(_param)); \ ptr = ((char*) ptr)+sizeof(_param); \ } while(0) /*** Packed events ***/ /** * \ingroup litl_write_pack * \brief Records a packed event without parameters * \param trace A pointer to the event recording object * \param code An event code */ #define litl_write_probe_pack_0(trace, \ code, \ retval) do { \ int total_size = 0; \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, total_size); \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 1 parameter * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event */ #define litl_write_probe_pack_1(trace, \ code, \ param1, \ retval) \ do { \ int total_size = sizeof(param1); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 2 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event */ #define litl_write_probe_pack_2(trace, \ code, \ param1, \ param2, \ retval) \ do { \ int total_size = sizeof(param1) + sizeof(param2); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 3 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event */ #define litl_write_probe_pack_3(trace, \ code, \ param1, \ param2, \ param3, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 4 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event */ #define litl_write_probe_pack_4(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 5 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event */ #define litl_write_probe_pack_5(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) +sizeof(param5); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 6 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event */ #define litl_write_probe_pack_6(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) + sizeof(param5) + sizeof(param6); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ __LITL_WRITE_ADD_ARG(_ptr_, param6); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 7 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event */ #define litl_write_probe_pack_7(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) + sizeof(param5) + sizeof(param6) \ + sizeof(param7); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ __LITL_WRITE_ADD_ARG(_ptr_, param6); \ __LITL_WRITE_ADD_ARG(_ptr_, param7); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 8 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event */ #define litl_write_probe_pack_8(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) + sizeof(param5) + sizeof(param6) \ + sizeof(param7) + sizeof(param8); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ __LITL_WRITE_ADD_ARG(_ptr_, param6); \ __LITL_WRITE_ADD_ARG(_ptr_, param7); \ __LITL_WRITE_ADD_ARG(_ptr_, param8); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 9 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event */ #define litl_write_probe_pack_9(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8, \ param9, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) + sizeof(param5) + sizeof(param6) \ + sizeof(param7) + sizeof(param8) + sizeof(param9); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ __LITL_WRITE_ADD_ARG(_ptr_, param6); \ __LITL_WRITE_ADD_ARG(_ptr_, param7); \ __LITL_WRITE_ADD_ARG(_ptr_, param8); \ __LITL_WRITE_ADD_ARG(_ptr_, param9); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_pack * \brief Records a packed event with 10 parameters * \param trace A pointer to the event recording object * \param code An event code * \param param1 1st parameter for this event * \param param2 2nd parameter for this event * \param param3 3rd parameter for this event * \param param4 4th parameter for this event * \param param5 5th parameter for this event * \param param6 6th parameter for this event * \param param7 7th parameter for this event * \param param8 8th parameter for this event * \param param9 9th parameter for this event * \param param10 10th parameter for this event */ #define litl_write_probe_pack_10(trace, \ code, \ param1, \ param2, \ param3, \ param4, \ param5, \ param6, \ param7, \ param8, \ param9, \ param10, \ retval) do { \ int total_size = sizeof(param1) + sizeof(param2) + \ sizeof(param3) + sizeof(param4) + sizeof(param5) + sizeof(param6) + \ sizeof(param7) + sizeof(param8) + sizeof(param9) + sizeof(param10); \ litl_t* p_evt = __litl_write_get_event(trace, \ LITL_TYPE_PACKED, \ code, \ total_size); \ if(p_evt){ \ void* _ptr_ = &p_evt->parameters.packed.param[0]; \ __LITL_WRITE_ADD_ARG(_ptr_, param1); \ __LITL_WRITE_ADD_ARG(_ptr_, param2); \ __LITL_WRITE_ADD_ARG(_ptr_, param3); \ __LITL_WRITE_ADD_ARG(_ptr_, param4); \ __LITL_WRITE_ADD_ARG(_ptr_, param5); \ __LITL_WRITE_ADD_ARG(_ptr_, param6); \ __LITL_WRITE_ADD_ARG(_ptr_, param7); \ __LITL_WRITE_ADD_ARG(_ptr_, param8); \ __LITL_WRITE_ADD_ARG(_ptr_, param9); \ __LITL_WRITE_ADD_ARG(_ptr_, param10); \ } \ retval = p_evt; \ } while(0) /** * \ingroup litl_write_init * \brief Finalizes the trace * \param trace A pointer to the event recording object */ void litl_write_finalize_trace(litl_write_trace_t* trace); #endif /* LITL_WRITE_H_ */ LiTL-litl-0.2/tests/000077500000000000000000000000001415666016500142755ustar00rootroot00000000000000LiTL-litl-0.2/tests/test_litl_buffer_size.c000066400000000000000000000052151415666016500210320ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test verifies the optimal buffer size for a single-threaded applications */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_types.h" #include "litl_timer.h" #include "litl_write.h" #include "litl_read.h" #define MAX_BUFFER_SIZE 16 * 1024 * 1024 #define NB_EVENTS 1000000 int main(int argc, char **argv) { int i; char* filename = "trace.trace"; uint32_t buf_size; litl_time_t start, fin; litl_write_trace_t* trace; if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else filename = "/tmp/test_litl_buffer_size.trace"; printf("What is the optimal buffer size for recording events?\n"); printf("Buffer size[KB] \t Time \n"); litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; buf_size = 1024; // 1KB while (buf_size <= MAX_BUFFER_SIZE) { trace = litl_write_init_trace(buf_size); litl_write_set_filename(trace, filename); start = litl_get_time(); for (i = 0; i < (NB_EVENTS + 1) / 12; i++) { litl_write_probe_reg_0(trace, 0x100 * (i + 1) + 1); litl_write_probe_reg_1(trace, 0x100 * (i + 1) + 2, 1); litl_write_probe_reg_2(trace, 0x100 * (i + 1) + 3, 1, 3); litl_write_probe_reg_3(trace, 0x100 * (i + 1) + 4, 1, 3, 5); litl_write_probe_reg_4(trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7); litl_write_probe_reg_5(trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11); litl_write_probe_reg_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13); litl_write_probe_reg_7(trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17); litl_write_probe_reg_8(trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19); litl_write_probe_reg_9(trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23); litl_write_probe_reg_10(trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29); litl_write_probe_raw(trace, 0x100 * (i + 1) + 12, sizeof(val) - 1, val); } fin = litl_get_time(); litl_write_finalize_trace(trace); printf("\t%"PRTIu32"\t\t %"PRTIu64"\n", buf_size / 1024, fin - start); buf_size = 2 * buf_size; } printf( "NB: time was measured only once on writing %d events to the %s file.\n\n", NB_EVENTS, filename); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_mapping_to_fxt.c000066400000000000000000000054661415666016500215550ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test validates the mapping between LiTL and FxT APIs */ #define _GNU_SOURCE #include #include #include #include #include #include "fxt.h" #include "fut.h" #define THREAD_ID pthread_self() int main() { int i, nb_iter; char* filename = "/tmp/test_litl_fxt_trace_size.trace"; const uint32_t buffer_size = 16 * 1024 * 1024; // 16MB nb_iter = 1000; fut_setup(buffer_size, FUT_KEYMASKALL, THREAD_ID); fut_set_filename(filename); enable_fut_flush() ; fut_enable_tid_logging() ; for (i = 0; i < nb_iter; i++) { // char events FUT_DO_PROBE0(0x100 * (i + 1) + 0); FUT_DO_PROBE1(0x100 * (i + 1) + 1, (uint8_t ) 1); FUT_DO_PROBE2(0x100 * (i + 1) + 2, (uint8_t ) 1, (uint8_t ) 3); FUT_DO_PROBE3(0x100 * (i + 1) + 3, (uint8_t ) 1, (uint8_t ) 3, (uint8_t ) 5); FUT_DO_PROBE4(0x100 * (i + 1) + 4, (uint8_t ) 1, (uint8_t ) 3, (uint8_t ) 5, (uint8_t ) 7); FUT_DO_PROBE5(0x100 * (i + 1) + 5, (uint8_t ) 1, (uint8_t ) 3, (uint8_t ) 5, (uint8_t ) 7, (uint8_t ) 11); FUT_DO_PROBE6(0x100 * (i + 1) + 6, (uint8_t ) 1, (uint8_t ) 3, (uint8_t ) 5, (uint8_t ) 7, (uint8_t ) 11, (uint8_t ) 13); usleep(10); // int events FUT_DO_PROBE0(0x100 * (i + 1) + 7); FUT_DO_PROBE1(0x100 * (i + 1) + 8, (int ) 1); FUT_DO_PROBE2(0x100 * (i + 1) + 9, (int ) 1, (int ) 3); FUT_DO_PROBE3(0x100 * (i + 1) + 10, (int ) 1, (int ) 3, (int ) 5); FUT_DO_PROBE4(0x100 * (i + 1) + 11, (int ) 1, (int ) 3, (int ) 5, (int ) 7); FUT_DO_PROBE5(0x100 * (i + 1) + 12, (int ) 1, (int ) 3, (int ) 5, (int ) 7, (int ) 11); FUT_DO_PROBE6(0x100 * (i + 1) + 13, (int ) 1, (int ) 3, (int ) 5, (int ) 7, (int ) 11, (int ) 13); usleep(10); // double events FUT_DO_PROBE0(0x100 * (i + 1) + 14); FUT_DO_PROBE1(0x100 * (i + 1) + 15, (double ) 1); FUT_DO_PROBE2(0x100 * (i + 1) + 16, (double ) 1, (double ) 3); FUT_DO_PROBE3(0x100 * (i + 1) + 17, (double ) 1, (double ) 3, (double ) 5); FUT_DO_PROBE4(0x100 * (i + 1) + 18, (double ) 1, (double ) 3, (double ) 5, (double ) 7); FUT_DO_PROBE5(0x100 * (i + 1) + 19, (double ) 1, (double ) 3, (double ) 5, (double ) 7, (double ) 11); FUT_DO_PROBE6(0x100 * (i + 1) + 20, (double ) 1, (double ) 3, (double ) 5, (double ) 7, (double ) 11, (double ) 13); usleep(10); } fut_endup(filename); fut_done(); long size; FILE* fp = fopen(filename, "r"); fseek(fp, 0L, SEEK_END); size = ftell(fp); fclose(fp); printf("Trace file size = %ld KB\n", size / 1024); // size in KB return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_pause.c000066400000000000000000000100031415666016500176330ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test simulates the situation when the event recoding is paused. */ #define _GNU_SOURCE #include #include #include #include #include "litl_types.h" #include "litl_tools.h" #include "litl_write.h" #include "litl_read.h" void write_trace(char* filename, int nb_iter, int skipped_iter) { int i; litl_write_trace_t* trace; const uint32_t buffer_size = 512 * 1024; // 512KB trace = litl_write_init_trace(buffer_size); litl_write_set_filename(trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(trace); #else litl_write_buffer_flush_off(trace); #endif litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; for (i = 0; i < nb_iter; i++) { if (i == skipped_iter - 1) { printf("Loop %d: stop recording\n", i); litl_write_pause_recording(trace); } litl_write_probe_reg_0(trace, 0x100 * (i + 1) + 1); usleep(100); litl_write_probe_reg_1(trace, 0x100 * (i + 1) + 2, 1); usleep(100); litl_write_probe_reg_2(trace, 0x100 * (i + 1) + 3, 1, 3); usleep(100); litl_write_probe_reg_3(trace, 0x100 * (i + 1) + 4, 1, 3, 5); usleep(100); litl_write_probe_reg_4(trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7); usleep(100); litl_write_probe_reg_5(trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11); usleep(100); litl_write_probe_reg_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13); usleep(100); litl_write_probe_reg_7(trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17); usleep(100); litl_write_probe_reg_8(trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19); usleep(100); litl_write_probe_reg_9(trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23); usleep(100); litl_write_probe_reg_10(trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29); usleep(100); litl_write_probe_raw(trace, 0x100 * (i + 1) + 12, sizeof(val) - 1, val); usleep(100); if (i == skipped_iter - 1) { printf("Loop %d: resume recording\n", i); litl_write_resume_recording(trace); } } printf("\nEvents with code between %x and %x were not recorded\n", 0x100 * skipped_iter + 1, 0x100 * skipped_iter + 12); litl_write_finalize_trace(trace); } void read_trace(char* filename, uint32_t left_bound, uint32_t right_bound) { int nbevents = 0; litl_read_event_t* event; litl_read_trace_t *trace; trace = litl_read_open_trace(filename); litl_read_init_processes(trace); while (1) { event = litl_read_next_event(trace); if (event == NULL ) break; // check whether some events were skipped if ((left_bound < LITL_READ_GET_CODE(event))&& (LITL_READ_GET_CODE(event) < right_bound)){ nbevents++; break; } } // litl_read_finalize_trace(trace); if (nbevents > 0) { fprintf(stderr, "Some events were recorded when they supposed to be skipped"); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { int nb_iter; int skipped_iter; char* filename = "trace"; nb_iter = 10; skipped_iter = nb_iter / 2; if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else #ifdef LITL_TESTBUFFER_FLUSH filename = "/tmp/test_litl_pause_flush.trace"; #else filename = "/tmp/test_litl_pause.trace"; #endif printf("Recording events with various number of arguments\n\n"); write_trace(filename, nb_iter, skipped_iter); printf("Events are recorded and written in the %s file\n", filename); printf("\nChecking whether the recording of events was paused\n"); read_trace(filename, 0x100 * skipped_iter + 1, 0x100 * skipped_iter + 12); printf("Yes, the recording of events was paused\n"); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_read.c000066400000000000000000000060041415666016500174370ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test validates the event reading mechanism */ #define _GNU_SOURCE #include #include #include #include "litl_types.h" #include "litl_tools.h" #include "litl_read.h" int main(int argc, const char **argv) { litl_data_t i; const char* filename = "trace"; litl_read_event_t* event; litl_read_trace_t *trace; litl_general_header_t* trace_header; litl_process_header_t* process_header; if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else #ifdef LITL_TESTBUFFER_FLUSH filename = "/tmp/test_litl_write_flush.trace"; #else filename = "/tmp/test_litl_write.trace"; #endif trace = litl_read_open_trace(filename); litl_read_init_processes(trace); trace_header = litl_read_get_trace_header(trace); process_header = litl_read_get_process_header(trace->processes[0]); // print the header printf(" LiTL v.%s\n", trace_header->litl_ver); printf(" %s\n", trace_header->sysinfo); printf(" nb_processes \t %d\n", trace_header->nb_processes); if (trace_header->nb_processes == 1) printf(" nb_threads \t %u\n", process_header->nb_threads); printf( " buffer_size \t %u\n", process_header->buffer_size - __litl_get_reg_event_size(LITL_MAX_PARAMS) - __litl_get_reg_event_size(0)); printf( "Thread ID\t Event Type & Code \t Time\t NB args\t Arguments[0-9]\n"); while (1) { event = litl_read_next_event(trace); if (event == NULL ) break; switch (LITL_READ_GET_TYPE(event)) { case LITL_TYPE_REGULAR: { // regular event printf("%"PRTIu64" \t Reg %"PRTIx32" \t %"PRTIu64" \t %"PRTIu32, LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_GET_TIME(event), LITL_READ_REGULAR(event)->nb_params); for (i = 0; i < LITL_READ_REGULAR(event)->nb_params; i++) printf("\t %"PRTIx64, LITL_READ_REGULAR(event)->param[i]); break; } case LITL_TYPE_RAW: { // raw event printf("%"PRTIu64" \t Raw %"PRTIx32" \t %"PRTIu64" \t %"PRTIu32, LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_GET_TIME(event), LITL_READ_RAW(event)->size); printf("\t %s", (litl_data_t *) LITL_READ_RAW(event)->data); break; } case LITL_TYPE_PACKED: { // packed event printf("%"PRTIu64" \t Packed %"PRTIx32" \t %"PRTIu64" \t %"PRTIu32, LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_GET_TIME(event), LITL_READ_PACKED(event)->size); for (i = 0; i < LITL_READ_PACKED(event)->size; i++) { printf(" %x", LITL_READ_PACKED(event)->param[i]); } break; } case LITL_TYPE_OFFSET: { // offset event continue; } default: { fprintf(stderr, "Unknown event type %d\n", LITL_READ_GET_TYPE(event)); *(int*) 0 = 0; } } printf("\n"); } litl_read_finalize_trace(trace); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_trace_size.c000066400000000000000000000030451415666016500206560ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test is to show that LiTL uses the optimized event storage and occupies * the required space only. */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_types.h" #include "litl_write.h" int main(int argc, char **argv) { int i, nb_iter; litl_write_trace_t* trace; char* filename = "trace"; const uint32_t buffer_size = 32 * 1024; // 32KB if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else filename = "/tmp/test_litl_trace_size.trace"; printf("Recording events with six arguments of type uint8_t\n\n"); trace = litl_write_init_trace(buffer_size); litl_write_set_filename(trace, filename); litl_write_buffer_flush_on(trace); nb_iter = 1000; for (i = 0; i < nb_iter; i++) { litl_t *retval; litl_write_probe_pack_6(trace, 0x100 * (i + 1) + 6, (int32_t ) 1, (int32_t ) 3, (int32_t ) 5, (int32_t ) 7, (int32_t ) 11, (int32_t ) 13, retval); assert(retval != NULL); usleep(100); } litl_write_finalize_trace(trace); printf("Events are recorded and written in the %s file\n", filename); long size; FILE* fp = fopen(filename, "r"); fseek(fp, 0L, SEEK_END); size = ftell(fp); fclose(fp); printf("\nThe size of the trace file with %d packed event6 is %ld bytes \n", nb_iter, size); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_write.c000066400000000000000000000050261415666016500176610ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test validates the event recording mechanism */ #define _GNU_SOURCE #include #include #include #include #include "litl_types.h" #include "litl_write.h" int main(int argc, char **argv) { int i, nb_iter; litl_write_trace_t* trace; char* filename = "trace"; const uint32_t buffer_size = 32 * 1024; // 32KB if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else #ifdef LITL_TESTBUFFER_FLUSH filename = "/tmp/test_litl_write_flush.trace"; #else filename = "/tmp/test_litl_write.trace"; #endif printf("Recording events with various number of arguments\n\n"); trace = litl_write_init_trace(buffer_size); litl_write_set_filename(trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(trace); #else litl_write_buffer_flush_off(trace); #endif nb_iter = 1000; litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; for (i = 0; i < (nb_iter + 1) / 12; i++) { litl_write_probe_reg_0(trace, 0x100 * (i + 1) + 1); usleep(100); litl_write_probe_reg_1(trace, 0x100 * (i + 1) + 2, 1); usleep(100); litl_write_probe_reg_2(trace, 0x100 * (i + 1) + 3, 1, 3); usleep(100); litl_write_probe_reg_3(trace, 0x100 * (i + 1) + 4, 1, 3, 5); usleep(100); litl_write_probe_reg_4(trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7); usleep(100); litl_write_probe_reg_5(trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11); usleep(100); litl_write_probe_reg_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13); usleep(100); litl_write_probe_reg_7(trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17); usleep(100); litl_write_probe_reg_8(trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19); usleep(100); litl_write_probe_reg_9(trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23); usleep(100); litl_write_probe_reg_10(trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29); usleep(100); litl_write_probe_raw(trace, 0x100 * (i + 1) + 12, sizeof(val), val); usleep(100); } litl_write_finalize_trace(trace); printf("Events are recorded and written in the %s file\n", filename); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_write_concurent.c000066400000000000000000000111321415666016500217340ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test simulates recording of events of multi-threaded applications. * The test ensures that LiTL solves the race conditions by recording events * into separate buffers: one per thread. * All the buffers are written to the same trace file */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_types.h" #include "litl_write.h" #include "litl_read.h" #define NBTHREAD 16 #define NBITER 100 #define NBEVENT (NBITER * 12) litl_write_trace_t* __trace; int total_recorded_events = 0; pthread_mutex_t mutex; /* * This test records several traces at the same time */ void* write_trace(void *arg __attribute__ ((__unused__))) { int i; litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; int nb_recorded_events = 0; #define TEST_WRITE_CHECK_RETVAL(cmd) \ do { \ litl_t* retval = cmd; \ if(retval) { \ nb_recorded_events++; \ } \ }while(0) for (i = 0; i < NBITER; i++) { TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_0(__trace, 0x100 * (i + 1) + 1)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_1(__trace, 0x100 * (i + 1) + 2, 1)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_2(__trace, 0x100 * (i + 1) + 3, 1, 3)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_3(__trace, 0x100 * (i + 1) + 4, 1, 3, 5)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_4(__trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_5(__trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_6(__trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_7(__trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_8(__trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_9(__trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_10(__trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_raw(__trace, 0x100 * (i + 1) + 12, sizeof(val), val)); usleep(100); } pthread_mutex_lock(&mutex); total_recorded_events += nb_recorded_events; pthread_mutex_unlock(&mutex); return NULL ; } void read_trace(char* filename) { int nb_events = 0; litl_read_event_t* event; litl_read_trace_t *trace; trace = litl_read_open_trace(filename); litl_read_init_processes(trace); while (1) { event = litl_read_next_event(trace); if (event == NULL ) break; nb_events++; } litl_read_finalize_trace(trace); if (nb_events != total_recorded_events) { fprintf( stderr, "Some events were NOT recorded!\n Expected nb_events = %d \t Recorded nb_events = %d\n", total_recorded_events, nb_events); exit(EXIT_FAILURE); } } int main() { int i, res __attribute__ ((__unused__)); char* filename; pthread_t tid[NBTHREAD]; const uint32_t buffer_size = 1024; // 1KB pthread_mutex_init(&mutex, NULL); printf("Recording events by %d threads\n\n", NBTHREAD); #ifdef LITL_TESTBUFFER_FLUSH res = asprintf(&filename, "/tmp/test_litl_write_concurent_flush.trace"); #else res = asprintf(&filename, "/tmp/test_litl_write_concurent.trace"); #endif __trace = litl_write_init_trace(buffer_size); litl_write_set_filename(__trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(__trace); #else litl_write_buffer_flush_off(__trace); #endif for (i = 0; i < NBTHREAD; i++) { pthread_create(&tid[i], NULL, write_trace, &i); } for (i = 0; i < NBTHREAD; i++) pthread_join(tid[i], NULL ); printf("All events are stored in %s\n\n", __trace->filename); litl_write_finalize_trace(__trace); printf("Checking the recording of events\n\n"); read_trace(filename); printf("Yes, the events were recorded successfully\n"); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_write_multiple_applications.c000066400000000000000000000063331415666016500243440ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test simulates recording of events by multiple threads simultaneously. * This test ensures that LiTL can be used by many applications at the same time */ #define _GNU_SOURCE #include #include #include #include #include #include #include "litl_types.h" #include "litl_write.h" #define NBTHREAD 4 /* * Only used during thread creating to make sure that the thread * got the correct args. */ sem_t thread_ready; /* * Records several traces at the same time */ void* write_trace(void* arg) { int i, res __attribute__ ((__unused__)); char* filename; uint8_t my_id = *(uint8_t*) arg; // Notify the main thread that we got the args sem_post(&thread_ready); printf("Recording events on thread #%d\n", my_id); #ifdef LITL_TESTBUFFER_FLUSH res = asprintf(&filename, "/tmp/test_litl_write_%d_flush.trace", my_id); #else res = asprintf(&filename, "/tmp/test_litl_write_%d.trace", my_id); #endif litl_write_trace_t* trace; const uint32_t buffer_size = 512 * 1024; // 512KB trace = litl_write_init_trace(buffer_size); litl_write_set_filename(trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(trace); #else litl_write_buffer_flush_off(trace); #endif int nb_iter = 1000; litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; for (i = 0; i < nb_iter; i++) { litl_write_probe_reg_0(trace, 0x100 * (i + 1) + 1); usleep(100); litl_write_probe_reg_1(trace, 0x100 * (i + 1) + 2, 1); usleep(100); litl_write_probe_reg_2(trace, 0x100 * (i + 1) + 3, 1, 3); usleep(100); litl_write_probe_reg_3(trace, 0x100 * (i + 1) + 4, 1, 3, 5); usleep(100); litl_write_probe_reg_4(trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7); usleep(100); litl_write_probe_reg_5(trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11); usleep(100); litl_write_probe_reg_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13); usleep(100); litl_write_probe_reg_7(trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17); usleep(100); litl_write_probe_reg_8(trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19); usleep(100); litl_write_probe_reg_9(trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23); usleep(100); litl_write_probe_reg_10(trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29); usleep(100); litl_write_probe_raw(trace, 0x100 * (i + 1) + 12, sizeof(val) - 1, val); usleep(100); } printf("Events for thread #%d are stored in %s\n", my_id, trace->filename); litl_write_finalize_trace(trace); return NULL ; } int main() { int i; pthread_t tid[NBTHREAD]; sem_init(&thread_ready, 0, 0); for (i = 0; i < NBTHREAD; i++) { pthread_create(&tid[i], NULL, write_trace, &i); sem_wait(&thread_ready); } for (i = 0; i < NBTHREAD; i++) pthread_join(tid[i], NULL ); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_write_multiple_threads.c000066400000000000000000000106421415666016500233060ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test is to simulate the situation when some threads start later than * the others while recording events of multi-threaded applications */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_types.h" #include "litl_write.h" #include "litl_read.h" #define NBTHREAD 16 #define NBITER 100 #define NBEVENT (NBITER * 12) static litl_write_trace_t* __trace; _Atomic int total_recorded_events = 0; /* * Records several traces at the same time */ void* write_trace(void *arg __attribute__ ((__unused__))) { int i; litl_data_t val[] = "Well, that's Philosophy I've read, And Law and Medicine, and I fear Theology, too, from A to Z; Hard studies all, that have cost me dear. And so I sit, poor silly man No wiser now than when I began."; int nb_recorded_events = 0; #define TEST_WRITE_CHECK_RETVAL(cmd) \ do { \ litl_t* retval = cmd; \ if(retval) nb_recorded_events++; \ }while(0) for (i = 0; i < NBITER; i++) { TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_0(__trace, 0x100 * (i + 1) + 1)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_1(__trace, 0x100 * (i + 1) + 2, 1)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_2(__trace, 0x100 * (i + 1) + 3, 1, 3)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_3(__trace, 0x100 * (i + 1) + 4, 1, 3, 5)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_4(__trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_5(__trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_6(__trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_7(__trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_8(__trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_9(__trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_reg_10(__trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29)); usleep(100); TEST_WRITE_CHECK_RETVAL(litl_write_probe_raw(__trace, 0x100 * (i + 1) + 12, sizeof(val), val)); usleep(100); } total_recorded_events += nb_recorded_events; return NULL ; } void read_trace(char* filename) { int nb_events = 0; litl_read_event_t* event; litl_read_trace_t *trace; trace = litl_read_open_trace(filename); litl_read_init_processes(trace); while (1) { event = litl_read_next_event(trace); if (event == NULL ) break; nb_events++; } litl_read_finalize_trace(trace); if (nb_events != total_recorded_events) { fprintf( stderr, "Some events were NOT recorded!\n Expected nb_events = %d \t Recorded nb_events = %d\n", total_recorded_events, nb_events); exit(EXIT_FAILURE); } } int main() { int i, res __attribute__ ((__unused__)); char* filename; pthread_t tid[NBTHREAD]; const uint32_t buffer_size = 1024; // 1KB printf("Recording events by %d threads\n\n", NBTHREAD); #ifdef LITL_TESTBUFFER_FLUSH res = asprintf(&filename, "/tmp/test_litl_write_multiple_threads_flush.trace"); #else res = asprintf(&filename, "/tmp/test_litl_write_multiple_threads.trace"); #endif __trace = litl_write_init_trace(buffer_size); litl_write_set_filename(__trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(__trace); #else litl_write_buffer_flush_off(__trace); #endif for (i = 0; i < NBTHREAD; i++) { pthread_create(&tid[i], NULL, write_trace, &i); if ((i + 1) % 4 == 0) { sleep(1); } } for (i = 0; i < NBTHREAD; i++) pthread_join(tid[i], NULL ); printf("All events are stored in %s\n\n", __trace->filename); litl_write_finalize_trace(__trace); printf("Checking the recording of events\n\n"); read_trace(filename); printf("Yes, the events were recorded successfully\n"); return EXIT_SUCCESS; } LiTL-litl-0.2/tests/test_litl_write_pack.c000066400000000000000000000067701415666016500206660ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /* * This test validates the event recording mechanism */ #define _GNU_SOURCE #include #include #include #include #include "litl_types.h" #include "litl_write.h" #include "litl_tools.h" const uint32_t buffer_size = 32 * 1024; // 32KB #ifdef LITL_TESTBUFFER_FLUSH /* since buffer flush is enabled, retval should always be not NULL */ #define CHECK_RETVAL(cmd, retval) do { \ cmd; \ if(!retval){ \ fprintf(stderr, "test failed at line %d\n", __LINE__); \ abort(); \ } \ } while(0) #else size_t total_size=0; #define CHECK_RETVAL(cmd, retval) do { \ cmd; \ if(!retval && total_size + __litl_get_reg_event_size(LITL_MAX_PARAMS) < buffer_size){ \ fprintf(stderr, "test failed at line %d\n", __LINE__); \ abort(); \ } \ if(retval) { \ total_size += __litl_get_gen_event_size(retval); \ } \ } while(0) #endif int main(int argc, char **argv) { int i, nb_iter; litl_write_trace_t* trace; char* filename = "trace"; if ((argc == 3) && (strcmp(argv[1], "-f") == 0)) filename = argv[2]; else #ifdef LITL_TESTBUFFER_FLUSH filename = "/tmp/test_litl_write_pack_flush.trace"; #else filename = "/tmp/test_litl_write_pack.trace"; #endif printf("Recording events with various number of arguments\n\n"); trace = litl_write_init_trace(buffer_size); litl_write_set_filename(trace, filename); #ifdef LITL_TESTBUFFER_FLUSH litl_write_buffer_flush_on(trace); #else litl_write_buffer_flush_off(trace); #endif nb_iter = 1000; for (i = 0; i < (nb_iter + 1) / 12; i++) { litl_t *retval = NULL; CHECK_RETVAL(litl_write_probe_pack_0(trace, 0x100 * (i + 1) + 1, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_1(trace, 0x100 * (i + 1) + 2, 1, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_2(trace, 0x100 * (i + 1) + 3, 1, 3, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_3(trace, 0x100 * (i + 1) + 4, 1, 3, 5, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_4(trace, 0x100 * (i + 1) + 5, 1, 3, 5, 7, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_5(trace, 0x100 * (i + 1) + 6, 1, 3, 5, 7, 11, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_6(trace, 0x100 * (i + 1) + 7, 1, 3, 5, 7, 11, 13, retval), retval); CHECK_RETVAL(litl_write_probe_pack_7(trace, 0x100 * (i + 1) + 8, 1, 3, 5, 7, 11, 13, 17, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_8(trace, 0x100 * (i + 1) + 9, 1, 3, 5, 7, 11, 13, 17, 19, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_9(trace, 0x100 * (i + 1) + 10, 1, 3, 5, 7, 11, 13, 17, 19, 23, retval), retval); usleep(100); CHECK_RETVAL(litl_write_probe_pack_10(trace, 0x100 * (i + 1) + 11, 1, 3, 5, 7, 11, 13, 17, 19, 23, 29, retval), retval); usleep(100); // litl_write_probe_raw(trace, 0x100 * (i + 1) + 12, sizeof(val), val); // usleep(100); } litl_write_finalize_trace(trace); printf("Events are recorded and written in the %s file\n", filename); return EXIT_SUCCESS; } LiTL-litl-0.2/utils/000077500000000000000000000000001415666016500142735ustar00rootroot00000000000000LiTL-litl-0.2/utils/CMakeLists.txt000066400000000000000000000007431415666016500170370ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1) add_executable(litl_print litl_print.c ) add_executable(litl_merge litl_merge.c ) add_executable(litl_split litl_split.c ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include> ) target_link_libraries( litl_print PRIVATE litl ) target_link_libraries( litl_merge PRIVATE litl ) target_link_libraries( litl_split PRIVATE litl ) install( TARGETS litl_print litl_merge litl_split ) LiTL-litl-0.2/utils/litl_merge.c000066400000000000000000000035311415666016500165640ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file utils/litl_merge.c * \brief litl_merge A utility for combining both regular trace files and * archives of traces into archives. The latter is the recursive inclusion * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #define _GNU_SOURCE #include #include #include #include #include #include "litl_merge.h" static char* __arch_name; static char** __trace_names; static int __nb_traces; static void __usage(int argc __attribute__((unused)), char **argv) { fprintf(stderr, "Usage: %s [-o archive_name] input_filename input_filename ... \n", argv[0]); printf(" -?, -h: Display this help and exit\n"); } static void __parse_args(int argc, char **argv) { int i, res __attribute__ ((__unused__)); __trace_names = (char **) malloc((argc - 3) * sizeof(char *)); __nb_traces = 0; for (i = 1; i < argc; i++) { if ((strcmp(argv[i], "-o") == 0)) { res = asprintf(&__arch_name, "%s", argv[++i]); } else if ((strcmp(argv[i], "-h") || strcmp(argv[i], "-?")) == 0) { __usage(argc, argv); exit(-1); } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option %s\n", argv[i]); __usage(argc, argv); exit(-1); } else { res = asprintf(&__trace_names[__nb_traces], "%s", argv[i]); __nb_traces++; } } if (__arch_name == NULL ) __usage(argc, argv); } int main(int argc, char **argv) { // parse the arguments passed to this program __parse_args(argc, argv); litl_merge_traces(__arch_name, __trace_names, __nb_traces); return EXIT_SUCCESS; } LiTL-litl-0.2/utils/litl_print.c000066400000000000000000000075561415666016500166340ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file utils/litl_print.c * \brief litl_print A utility for reading events from both regular trace * files and archives of traces * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #include #include #include "litl_tools.h" #include "litl_read.h" static char* __input_filename = "trace"; static void __litl_read_usage(int argc __attribute__((unused)), char **argv) { fprintf(stderr, "Usage: %s [-f input_filename] \n", argv[0]); printf(" -?, -h: Display this help and exit\n"); } static void __litl_read_parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if ((strcmp(argv[i], "-f") == 0)) { __input_filename = argv[++i]; } else if ((strcmp(argv[i], "-h") || strcmp(argv[i], "-?")) == 0) { __litl_read_usage(argc, argv); exit(-1); } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option %s\n", argv[i]); __litl_read_usage(argc, argv); exit(-1); } } if (strcmp(__input_filename, "trace") == 0) { __litl_read_usage(argc, argv); exit(-1); } } int main(int argc, char **argv) { litl_med_size_t i; litl_read_event_t* event; litl_read_trace_t *trace; litl_general_header_t* trace_header; litl_process_header_t* process_header; // parse the arguments passed to this program __litl_read_parse_args(argc, argv); trace = litl_read_open_trace(__input_filename); litl_read_init_processes(trace); trace_header = litl_read_get_trace_header(trace); process_header = litl_read_get_process_header(trace->processes[0]); // print the header printf(" LiTL v.%s\n", trace_header->litl_ver); printf(" %s\n", trace_header->sysinfo); printf(" nb_processes \t %d\n", trace_header->nb_processes); if (trace_header->nb_processes == 1) printf(" nb_threads \t %d\n", process_header->nb_threads); printf( " buffer_size \t %d\n", trace->processes[0]->header->buffer_size - __litl_get_reg_event_size(LITL_MAX_PARAMS) - __litl_get_reg_event_size(0)); printf( "[Timestamp]\t[ThreadID]\t[EventType]\t[EventCode]\t[NbParam]\t[Parameters]\n"); while (1) { event = litl_read_next_event(trace); if (event == NULL ) break; switch (LITL_READ_GET_TYPE(event)) { case LITL_TYPE_REGULAR: { // regular event printf("%"PRTIu64" \t%"PRTIu64" \t Reg %"PRTIx32" \t %"PRTIu32, LITL_READ_GET_TIME(event), LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_REGULAR(event)->nb_params); for (i = 0; i < LITL_READ_REGULAR(event)->nb_params; i++) printf("\t %"PRTIx64, LITL_READ_REGULAR(event)->param[i]); break; } case LITL_TYPE_RAW: { // raw event printf("%"PRTIu64"\t%"PRTIu64" \t Raw %"PRTIx32" \t %"PRTIu32, LITL_READ_GET_TIME(event), LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_RAW(event)->size); printf("\t %s", (litl_data_t *) LITL_READ_RAW(event)->data); break; } case LITL_TYPE_PACKED: { // packed event printf("%"PRTIu64" \t%"PRTIu64" \t Packed %"PRTIx32" \t %"PRTIu32"\t", LITL_READ_GET_TIME(event), LITL_READ_GET_TID(event), LITL_READ_GET_CODE(event), LITL_READ_PACKED(event)->size); for (i = 0; i < LITL_READ_PACKED(event)->size; i++) { printf(" %x", LITL_READ_PACKED(event)->param[i]); } break; } case LITL_TYPE_OFFSET: { // offset event continue; } default: { fprintf(stderr, "Unknown event type %d\n", LITL_READ_GET_TYPE(event)); abort(); } } printf("\n"); } litl_read_finalize_trace(trace); return EXIT_SUCCESS; } LiTL-litl-0.2/utils/litl_split.c000066400000000000000000000033101415666016500166130ustar00rootroot00000000000000/* -*- c-file-style: "GNU" -*- */ /* * Copyright © Télécom SudParis. * See COPYING in top-level directory. */ /** * \file utils/litl_split.c * \brief litl_split A utility for disassembling archives of traces into * separate regular trace files * * \authors * Developers are: \n * Roman Iakymchuk -- roman.iakymchuk@telecom-sudparis.eu \n * Francois Trahay -- francois.trahay@telecom-sudparis.eu \n */ #define _GNU_SOURCE #include #include #include #include #include "litl_split.h" static char *__archive_name = ""; static char *__output_dir = ""; static void __usage(int argc __attribute__((unused)), char **argv) { fprintf(stderr, "Usage: %s [-f archive_traces] [-d output_dir] \n", argv[0]); printf(" -?, -h: Display this help and exit\n"); } static void __parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if ((strcmp(argv[i], "-f") == 0)) { __archive_name = argv[++i]; } else if ((strcmp(argv[i], "-d") == 0)) { __output_dir = argv[++i]; } else if ((strcmp(argv[i], "-h") || strcmp(argv[i], "-?")) == 0) { __usage(argc, argv); exit(-1); } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option %s\n", argv[i]); __usage(argc, argv); exit(-1); } } if (strcmp(__archive_name, "") == 0) { __usage(argc, argv); exit(-1); } else if (strcmp(__output_dir, "") == 0) { __usage(argc, argv); exit(-1); } } int main(int argc, char **argv) { // parse the arguments passed to this program __parse_args(argc, argv); // split the archive litl_split_archive(__archive_name, __output_dir); return EXIT_SUCCESS; }