From d40edf7dac6e283bdf223e7ed96d2e0f36b5cbe2 Mon Sep 17 00:00:00 2001 From: dzambare Date: Tue, 7 Apr 2020 08:48:59 +0530 Subject: [PATCH] Execution and Debug trace support. Added support add debug logging, execution trace and decode. Change-Id: I024bf6165daa9e23a62423f2401c0f1c5de459ba AMD-Internal: [CPUPL-806] --- Makefile | 30 +++ aocl_dtl/aocldtl.c | 478 +++++++++++++++++++++++++++++++++++++ aocl_dtl/aocldtl.h | 156 ++++++++++++ aocl_dtl/aocldtlcf.h | 61 +++++ aocl_dtl/aoclfal.c | 265 ++++++++++++++++++++ aocl_dtl/aoclfal.h | 50 ++++ aocl_dtl/aoclflist.c | 150 ++++++++++++ aocl_dtl/aoclflist.h | 46 ++++ aocl_dtl/aoclos.c | 73 ++++++ aocl_dtl/aoclos.h | 27 +++ aocl_dtl/aocltpdef.h | 38 +++ aocl_dtl/etrace_decoder.py | 175 ++++++++++++++ aocl_dtl/test_dtl.c | 101 ++++++++ common.mk | 29 ++- config/zen/make_defs.mk | 10 + config/zen2/make_defs.mk | 15 ++ configure | 27 ++- frame/base/bli_init.c | 2 + frame/include/blis.h | 3 +- 19 files changed, 1728 insertions(+), 8 deletions(-) create mode 100644 aocl_dtl/aocldtl.c create mode 100644 aocl_dtl/aocldtl.h create mode 100644 aocl_dtl/aocldtlcf.h create mode 100644 aocl_dtl/aoclfal.c create mode 100644 aocl_dtl/aoclfal.h create mode 100644 aocl_dtl/aoclflist.c create mode 100644 aocl_dtl/aoclflist.h create mode 100644 aocl_dtl/aoclos.c create mode 100644 aocl_dtl/aoclos.h create mode 100644 aocl_dtl/aocltpdef.h create mode 100755 aocl_dtl/etrace_decoder.py create mode 100644 aocl_dtl/test_dtl.c diff --git a/Makefile b/Makefile index 06328bb1e..02846cd9f 100644 --- a/Makefile +++ b/Makefile @@ -112,6 +112,7 @@ BASE_OBJ_PATH := ./$(OBJ_DIR)/$(CONFIG_NAME) # of source code. BASE_OBJ_CONFIG_PATH := $(BASE_OBJ_PATH)/$(CONFIG_DIR) BASE_OBJ_FRAME_PATH := $(BASE_OBJ_PATH)/$(FRAME_DIR) +BASE_OBJ_AOCLDTL_PATH := $(BASE_OBJ_PATH)/$(AOCLDTL_DIR) BASE_OBJ_REFKERN_PATH := $(BASE_OBJ_PATH)/$(REFKERN_DIR) BASE_OBJ_KERNELS_PATH := $(BASE_OBJ_PATH)/$(KERNELS_DIR) BASE_OBJ_SANDBOX_PATH := $(BASE_OBJ_PATH)/$(SANDBOX_DIR) @@ -209,6 +210,11 @@ MK_REFKERN_OBJS := $(foreach arch, $(CONFIG_LIST), \ # Generate object file paths for all of the portable framework source code. MK_FRAME_OBJS := $(call gen-obj-paths-from-src,$(FRAME_SRC_SUFS),$(MK_FRAME_SRC),$(FRAME_PATH),$(BASE_OBJ_FRAME_PATH)) +# Generate object file paths for all of the debgu and trace logger. +MK_AOCLDTL_OBJS := $(call gen-obj-paths-from-src,$(AOCLDTL_SRC_SUFS),$(MK_AOCLDTL_SRC),$(AOCLDTL_PATH),$(BASE_OBJ_AOCLDTL_PATH)) + + + # Generate object file paths for the sandbox source code. If a sandbox was not # enabled a configure-time, this variable will we empty. MK_SANDBOX_OBJS := $(call gen-obj-paths-from-src,$(SANDBOX_SRC_SUFS),$(MK_SANDBOX_SRC),$(SANDBOX_PATH),$(BASE_OBJ_SANDBOX_PATH)) @@ -218,6 +224,7 @@ MK_BLIS_OBJS := $(MK_CONFIG_OBJS) \ $(MK_KERNELS_OBJS) \ $(MK_REFKERN_OBJS) \ $(MK_FRAME_OBJS) \ + $(MK_AOCLDTL_OBJS) \ $(MK_SANDBOX_OBJS) # Optionally filter out the BLAS and CBLAS compatibility layer object files. @@ -508,6 +515,18 @@ else endif endef +# first argument: a configuration name from the union of config_list and +# config_name, used to look up the CFLAGS to use during compilation. +define make-aocldtl-rule +$(BASE_OBJ_AOCLDTL_PATH)/%.o: $(AOCLDTL_PATH)/%.c $(BLIS_H_FLAT) $(MAKE_DEFS_MK_PATHS) +ifeq ($(ENABLE_VERBOSE),yes) + $(CC) $(call get-aocldtl-cflags-for,$(1)) -c $$< -o $$@ +else + @echo "Compiling $$@" $(call get-aocldtl-text-for,$(1)) + @$(CC) $(call get-aocldtl-cflags-for,$(1)) -c $$< -o $$@ +endif +endef + # first argument: a kernel set (name) being targeted (e.g. haswell). define make-refinit-rule $(BASE_OBJ_REFKERN_PATH)/$(1)/bli_cntx_$(1)_ref.o: $(REFKERN_PATH)/bli_cntx_ref.c $(BLIS_H_FLAT) $(MAKE_DEFS_MK_PATHS) @@ -583,6 +602,14 @@ $(foreach conf, $(CONFIG_LIST), $(eval $(call make-config-rule,$(conf)))) # item.) $(foreach conf, $(CONFIG_NAME), $(eval $(call make-frame-rule,$(conf)))) +# Instantiate the build rule for debug and trace log. Use the CFLAGS for the +# configuration family, which exists in the directory whose name is equal to +# CONFIG_NAME. Note that this doesn't need to be in a loop since we expect +# CONFIG_NAME to only ever contain a single name. (BTW: If CONFIG_NAME refers +# to a singleton family, then CONFIG_LIST contains CONFIG_NAME as its only +# item.) +$(foreach conf, $(CONFIG_NAME), $(eval $(call make-aocldtl-rule,$(conf)))) + # Instantiate the build rule for reference kernel initialization and # reference kernels for each of the sub-configurations in CONFIG_LIST with # the CFLAGS designated for that sub-configuration. @@ -1053,6 +1080,7 @@ ifeq ($(IS_CONFIGURED),yes) ifeq ($(ENABLE_VERBOSE),yes) - $(FIND) $(CONFIG_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) - $(FIND) $(FRAME_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) + - $(FIND) $(AOCLDTL_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) - $(FIND) $(REFKERN_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) - $(FIND) $(KERNELS_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) ifneq ($(SANDBOX),) @@ -1063,6 +1091,8 @@ else @- $(FIND) $(CONFIG_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) @echo "Removing makefile fragments from $(FRAME_FRAG_PATH)" @- $(FIND) $(FRAME_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) + @echo "Removing makefile fragments from $(AOCLDTL_FRAG_PATH)" + @- $(FIND) $(AOCLDTL_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) @echo "Removing makefile fragments from $(REFKERN_FRAG_PATH)" @- $(FIND) $(REFKERN_FRAG_PATH) -name "$(FRAGMENT_MK)" | $(XARGS) $(RM_F) @echo "Removing makefile fragments from $(KERNELS_FRAG_PATH)" diff --git a/aocl_dtl/aocldtl.c b/aocl_dtl/aocldtl.c new file mode 100644 index 000000000..249ad5c5d --- /dev/null +++ b/aocl_dtl/aocldtl.c @@ -0,0 +1,478 @@ +/*=================================================================== + * File Name : aocldtl.c + * + * Description : This file contains main logging functions. + * These functions are invoked though macros by + * end user. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#include "aocltpdef.h" +#include "aocldtl.h" +#include "aoclfal.h" +#include "aocldtlcf.h" +#include "aoclflist.h" +#include "aoclos.h" + +#ifdef AOCL_DTL_AUTO_TRACE_ENABLE +#if defined(__linux__) +#define __USE_GNU +#include +#endif +#endif + +/* The user can configure the file name in which he wants to dump the data */ +#if AOCL_DTL_TRACE_ENABLE + +/* The file name for storing traced log added manually in the code */ +static char *pchDTL_TRACE_FILE = AOCL_DTL_TRACE_FILE; + +/* Global file pointer for trace logging */ +AOCL_FLIST_Node *gpTraceFileList = NULL; + +/* By default the trace level will be set to ALL User can configure this + parameter at run time using command line argument */ +uint32 gui32TraceLogLevel = AOCL_DTL_LEVEL_ALL; +#endif + +#if AOCL_DTL_LOG_ENABLE +/* The file name for storing log data */ +static char *pchDTL_LOG_FILE = AOCL_DTL_LOG_FILE; + +/* Global file pointer for logging the results */ +AOCL_FLIST_Node *gpLogFileList = NULL; +#endif + +#if AOCL_DTL_AUTO_TRACE_ENABLE + +/* The file name for storing execution trace, + These files are used by compiler assisted execution testing */ +static char *pchDTL_AUTO_TRACE_FILE = AOCL_DTL_AUTO_TRACE_FILE; + +/* Global file pointer for logging the results */ +AOCL_FLIST_Node *gpAutoTraceFileList = NULL; +#endif + +/*=================================================================== +* Function Name : DTL_Initialize +* Description : Creates/Opens log file and initializes the +* global trace log level +* Input Parameter(s) : ui32CurrentLogLevel - current log level +* which user can configure at run time +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +#ifdef AOCL_DTL_INITIALIZE_ENABLE + +void DTL_Initialize( + uint32 ui32CurrentLogLevel) +{ + /* If user selects invalid trace log level then the dafault trace log level + will be AOCL_DTL_LEVEL_ALL */ + if ((ui32CurrentLogLevel < 1) || (ui32CurrentLogLevel > 4)) + { + ui32CurrentLogLevel = AOCL_DTL_LEVEL_ALL; + } + +#if AOCL_DTL_TRACE_ENABLE + /* Create/Open the file to log the traced data */ + AOCL_FLIST_AddFile(pchDTL_TRACE_FILE, &gpTraceFileList, AOCL_gettid()); + + if (NULL == gpTraceFileList) + { + /* Unable to open the specified file.*/ + AOCL_DEBUGPRINT("Unable to create the trace file %s\n", pchDTL_TRACE_FILE); + return; + } + + /* Assign the user requested log level to the global trace log level */ + gui32TraceLogLevel = ui32CurrentLogLevel; +#endif + +#if AOCL_DTL_LOG_ENABLE + /* Create/Open the file to log the log data */ + AOCL_FLIST_AddFile(pchDTL_LOG_FILE, &gpLogFileList, AOCL_gettid()); + + if (NULL == gpLogFileList) + { + /* Unable to open the specified file.*/ + AOCL_DEBUGPRINT("Unable to create the log file %s\n", pchDTL_LOG_FILE); + return; + } +#endif + +#if AOCL_DTL_AUTO_TRACE_ENABLE + /* Create/Open the file to log the log data */ + AOCL_FLIST_AddFile(pchDTL_AUTO_TRACE_FILE, &gpAutoTraceFileList, AOCL_gettid()); + + if (NULL == gpAutoTraceFileList) + { + /* Unable to open the specified file.*/ + AOCL_DEBUGPRINT("Unable to create the log file %s\n", pchDTL_AUTO_TRACE_FILE); + return; + } +#endif + +} /* DTL_Initialize */ +#endif + +/*=================================================================== +* Function Name : DTL_Uninitialize +* Description : Close all the log files +* Input Parameter(s) : void +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +#ifdef AOCL_DTL_INITIALIZE_ENABLE +void DTL_Uninitialize(void) +{ +#if AOCL_DTL_TRACE_ENABLE + /* Close the trace file */ + AOCL_FLIST_CloseAll(gpTraceFileList); +#endif + +#if AOCL_DTL_LOG_ENABLE + /* Close the log file */ + AOCL_FLIST_CloseAll(gpLogFileList); +#endif + +#if AOCL_DTL_AUTO_TRACE_ENABLE + /* Close the log file */ + AOCL_FLIST_CloseAll(gpAutoTraceFileList); +#endif + return; +} /* DTL_Uninitialise */ +#endif + +/*=================================================================== +* Function Name : DTL_Trace +* Description : This is common lowest level function +* to log the event to a file, This function +* will take case of choosing correct file +* according to the current thread and +* log the event as per format requested. + +* Input Parameter(s) : ui8LogLevel - Log Level +* ui8LogType - Identify log type (entry, exit etc) +* pi8FileName.- File name +* pi8FunctionName - Function Name +* ui32LineNumber - Line number +* pi8Message - Message to be printed +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +#if (AOCL_DTL_TRACE_ENABLE || AOCL_DTL_LOG_ENABLE) +void DTL_Trace( + uint8 ui8LogLevel, + uint8 ui8LogType, + const int8 *pi8FileName, + const int8 *pi8FunctionName, + uint32 ui32LineNumber, + const int8 *pi8Message) +{ + uint8 i = 0; + AOCL_FAL_FILE *pOutFile = NULL; + + if (ui8LogType == TRACE_TYPE_LOG || ui8LogType == TRACE_TYPE_RAW) + { + + pOutFile = AOCL_FLIST_GetFile(gpLogFileList, AOCL_gettid()); + + /* If trace file pointer is equal to NULL then return with out dumping data + to the file */ + if (NULL == pOutFile) + { + /* It might be the first call from the current thread, try to create + new trace for this thread. */ + pOutFile = AOCL_FLIST_AddFile(pchDTL_LOG_FILE, &gpLogFileList, AOCL_gettid()); + + if (NULL == pOutFile) + { + AOCL_DEBUGPRINT("File does not exists to dump the trace data \n"); + return; + } + } + } + else + { + + pOutFile = AOCL_FLIST_GetFile(gpTraceFileList, AOCL_gettid()); + + /* If trace file pointer is equal to NULL then return with out dumping data + to file */ + if (NULL == pOutFile) + { + /* It might be the first call from the current thread, try to create + new trace for this thread. */ + pOutFile = AOCL_FLIST_AddFile(pchDTL_TRACE_FILE, &gpTraceFileList, AOCL_gettid()); + + if (NULL == pOutFile) + { + AOCL_DEBUGPRINT("File does not exists to dump the trace data \n"); + return; + } + } + } + + /* Log the message only if the log level is less than or equal to global log + level set while initialization */ + if (ui8LogLevel <= gui32TraceLogLevel) + { + /* this loop is for formating the output log file */ + for (i = 0; i < ui8LogLevel; i++) + { + /* print tabs in the output file */ + fprintf(pOutFile, "\t"); + } + + switch (ui8LogType) + { + case TRACE_TYPE_FENTRY: + fprintf(pOutFile, "Entering %s()...\n", pi8FunctionName); + break; + + case TRACE_TYPE_FEXIT: + if (pi8Message == NULL) + { /* Function returned successfully */ + fprintf(pOutFile, "Returning from %s()\n", pi8FunctionName); + } + else + { /* Function failed to complete, use message to get error */ + fprintf(pOutFile, "Returning from %s() with error %s\n", pi8FunctionName, pi8Message); + } + break; + + case TRACE_TYPE_LOG: + fprintf(pOutFile, "%s:%d:%s\n", pi8FileName, ui32LineNumber, pi8Message); + break; + + case TRACE_TYPE_RAW: + fprintf(pOutFile, "%s\n", pi8Message); + break; + } + } +} /* DTL_Data_Trace_Entry */ +#endif + +/*=================================================================== +* Function Name : DTL_DumpData +* Description : This function is mainly used for dumping +* the data into the file +* Input Parameter(s) : pui8Buffer - the buffer to be dumped +* ui32BufferSize.- the no. of bytes to be dumped +* ui8DataType - the data type char/int32/int32 +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +#if AOCL_DTL_DUMP_ENABLE +void DTL_DumpData( + uint8 ui8LogLevel, + void *pvBuffer, + uint32 ui32BufferSize, + uint8 ui8DataType, + int8 *pi8Message, + int8 i8OutputType) +{ + uint32 j; + + /* Pointer to store the buffer */ + uint32 *pui32Array, ui32LocalData; + uint16 *pui16Array; + uint8 *pui8CharArray; + int8 *pi8CharString; + + /* If dump (log) file pointer is equal to NULL return with out dumping data to file */ + AOCL_FAL_FILE *pDumpFile = AOCL_FLIST_GetFile(gpLogFileList, AOCL_gettid()); + /* Log the message only if the log level is less than or equal to global log + level set while initialization */ + if (ui8LogLevel > gui32TraceLogLevel) + { + return; + } + + /* The string message */ + if (pi8Message != NULL) + { + fprintf(pDumpFile, "%s :", pi8Message); + } + + /* Assuming that if the Data type for character = 1 + * the Data type for uint32 = 2 + * the data type for uint32 = 4 + * the data type for string = 3 + */ + if (ui8DataType == AOCL_STRING_DATA_TYPE) + { + /* Typecast the void buffer to character buffer */ + pi8CharString = (int8 *)pvBuffer; + fprintf(pDumpFile, "%s", pi8CharString); + fprintf(pDumpFile, "\n"); + } + + if (ui8DataType == AOCL_CHAR_DATA_TYPE) + { + /* Typecast the void buffer to character buffer */ + pui8CharArray = (uint8 *)pvBuffer; + + for (j = 0; j < ui32BufferSize; j++) + { + if (i8OutputType == AOCL_LOG_HEX_VALUE) + { + fprintf(pDumpFile, "\n\t%5d:0x%x", j, pui8CharArray[j]); + } + else + { + fprintf(pDumpFile, "\n\t%5d:%u", j, pui8CharArray[j]); + } + } + fprintf(pDumpFile, "\n"); + } + + if (ui8DataType == AOCL_UINT16_DATA_TYPE) + { + /* Typecast the void buffer to uint32 bit buffer */ + pui16Array = (uint16 *)pvBuffer; + + /* dump the data in the file line by line */ + for (j = 0; j < ui32BufferSize; j++) + { + if (i8OutputType == AOCL_LOG_HEX_VALUE) + { + fprintf(pDumpFile, "\n\t%5d:0x%x", j, pui16Array[j]); + } + else + { + fprintf(pDumpFile, "\n\t%5d:%u", j, pui16Array[j]); + } + } + fprintf(pDumpFile, "\n"); + + } /* End of if */ + + if (ui8DataType == AOCL_UINT32_DATA_TYPE) + { + /* Typecast the void buffer to uint32 buffer */ + pui32Array = (uint32 *)pvBuffer; + + /* dump the data in the file line by line */ + for (j = 0; j < ui32BufferSize; j++) + { + ui32LocalData = pui32Array[j]; + + if (i8OutputType == AOCL_LOG_HEX_VALUE) + { + fprintf(pDumpFile, "\n\t%5d:0x%x", j, ui32LocalData); + } + else + { + fprintf(pDumpFile, "\n\t%5d:%u", j, ui32LocalData); + } + } + fprintf(pDumpFile, "\n"); + } /* End of if */ + +} /* DTL_DumpData */ +#endif + +/* This is enabled by passing ETRACE_ENABLE=1 to make */ +#ifdef AOCL_DTL_AUTO_TRACE_ENABLE + +/* + Disable intrumentation for these functions as they will also be + called from compiler generated instumation code to trace + function execution. + + It needs to be part of declration in the C file so can't be + moved to header file. + + WARNING: These functions are automatically invoked. however any function + called from this should have instumtation disable to avoid recursive + calls which results in hang/crash. + */ +void __cyg_profile_func_enter(void *this_fn, void *call_site) __attribute__((no_instrument_function)); +void __cyg_profile_func_exit(void *this_fn, void *call_site) __attribute__((no_instrument_function)); + +/*=================================================================== +* Function Name : __cyg_profile_func_enter +* Description : This function is automatically invoked +* by compiler instrumntation when the flow +* enters a function. +* Input Parameter(s) : pvThisFunc - Address of function entered. +* call_site.- Address of the caller +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +void __cyg_profile_func_enter(void *pvThisFunc, void *pvCaller) +{ + Dl_info info; + dladdr(pvThisFunc, &info); + + AOCL_FAL_FILE *pOutFile = NULL; + + pOutFile = AOCL_FLIST_GetFile(gpAutoTraceFileList, AOCL_gettid()); + + /* If trace file pointer is equal to NULL then return with out dumping data + to the file */ + if (NULL == pOutFile) + { + /* It might be the first call from the current thread, try to create + new trace for this thread. */ + pOutFile = AOCL_FLIST_AddFile(pchDTL_AUTO_TRACE_FILE, &gpAutoTraceFileList, AOCL_gettid()); + + if (NULL == pOutFile) + { + AOCL_DEBUGPRINT("File does not exists to dump the trace data \n"); + return; + } + } + + fprintf(pOutFile, "\n%u:%lu:+:%p", + AOCL_gettid(), + AOCL_getTimestamp(), + (void *)(pvThisFunc - info.dli_fbase)); +} + +/*=================================================================== +* Function Name : __cyg_profile_func_exit +* Description : This function is automatically invoked +* by compiler before returing from a +* function. +* Input Parameter(s) : pvThisFunc - Address of function to be existed. +* call_site.- Address of the caller +* Output Parameter(s) : None +* Return parameter(s) : None +*==================================================================*/ +void __cyg_profile_func_exit(void *pvThisFunc, void *pvCaller) +{ + Dl_info info; + dladdr(pvThisFunc, &info); + AOCL_FAL_FILE *pOutFile = NULL; + + pOutFile = AOCL_FLIST_GetFile(gpAutoTraceFileList, AOCL_gettid()); + + /* If trace file pointer is equal to NULL then return with out dumping data + to the file */ + if (NULL == pOutFile) + { + /* It might be the first call from the current thread, try to create + new trace for this thread. */ + pOutFile = AOCL_FLIST_AddFile(pchDTL_AUTO_TRACE_FILE, &gpAutoTraceFileList, AOCL_gettid()); + + if (NULL == pOutFile) + { + AOCL_DEBUGPRINT("File does not exists to dump the trace data \n"); + return; + } + } + + fprintf(pOutFile, "\n%u:%lu:-:%p", + AOCL_gettid(), + AOCL_getTimestamp(), + (void *)(pvThisFunc - info.dli_fbase)); +} + +#endif /* AOCL_AUTO_TRACE_ENABLE */ + +/* ------------------ End of aocldtl.c ---------------------- */ diff --git a/aocl_dtl/aocldtl.h b/aocl_dtl/aocldtl.h new file mode 100644 index 000000000..90d79ca17 --- /dev/null +++ b/aocl_dtl/aocldtl.h @@ -0,0 +1,156 @@ +/*=================================================================== + * File Name : aocldtl.h + * + * Description : This is main interface file for the end user + * It provides defination for all macros to be + * used by user to add debug/trace information. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#ifndef _AOCLDTL_H_ +#define _AOCLDTL_H_ + +#include "aocldtlcf.h" +#include "aocltpdef.h" +#include "aoclflist.h" + +#define TRACE_TYPE_FENTRY (1) +#define TRACE_TYPE_FEXIT (2) +#define TRACE_TYPE_LOG (3) +#define TRACE_TYPE_RAW (4) + +/* Type definition for printf */ +#define AOCL_DEBUGPRINT printf + +/* Define the AOCL_DTL_INITIALIZE_ENABLE if any of the debug macro + * are defined */ +#if (AOCL_DTL_TRACE_ENABLE || AOCL_DTL_DUMP_ENABLE || AOCL_DTL_LOG_ENABLE) +#define AOCL_DTL_INITIALIZE_ENABLE +#endif + +#if AOCL_DTL_TRACE_ENABLE +/* Entry macro to trace the flow of control The parameter LogLevel specifies + the log level String will preferably contains the function name in which + this macro is invoked */ +#define AOCL_DTL_TRACE_ENTRY(LogLevel) \ + DTL_Trace(LogLevel, \ + TRACE_TYPE_FENTRY, \ + __FILE__, \ + __FUNCTION__, \ + __LINE__, \ + NULL); +#else +/* Dummy macro definition if the AOCL_DTL_TRACE_ENABLE macro is not enabled */ +#define AOCL_DTL_TRACE_ENTRY(LogLevel) +#endif + +#if AOCL_DTL_TRACE_ENABLE +/* Exit macro to trace the flow of control The parameter LogLevel specifies + log level String will preferably contains the function name in which this + macro is invoked */ +#define AOCL_DTL_TRACE_EXIT(LogLevel) \ + DTL_Trace(LogLevel, \ + TRACE_TYPE_FEXIT, \ + __FILE__, \ + __FUNCTION__, \ + __LINE__, \ + NULL); + +#define AOCL_DTL_TRACE_EXIT_ERR(LogLevel, Message) \ + DTL_Trace(LogLevel, \ + TRACE_TYPE_FEXIT, \ + __FILE__, \ + __FUNCTION__, \ + __LINE__, \ + Message); +#else +/* Dummy macro definition if the AOCL_DTL_TRACE_ENABLE macro is not enabled */ +#define AOCL_DTL_TRACE_EXIT(LogLevel) +#define AOCL_DTL_TRACE_EXIT_ERR(LogLevel, Message) +#endif + +#if AOCL_DTL_DUMP_ENABLE +/* Macro to Dump the DATA The parameters Buffer contains the data to be + dumped BufferSize specifies the no. of bytes to be dumped DataType + specifies the data type of Buffer */ +#define AOCL_DTL_DUMP(LogLevel, Buffer, BufferSize, DataType, String, OutputType) \ + /* Call the Dump function to Dump the DATA */ \ + DTL_DumpData(LogLevel, \ + Buffer, \ + BufferSize, \ + DataType, \ + String, \ + OutputType); +#else +/* Dummy macro definition if the AOCL_DTL_DUMP_ENABLE macro is not enabled */ +#define AOCL_DTL_DUMP(Buffer, BufferSize, DataType, String, OutputType) + +#endif + +#if AOCL_DTL_LOG_ENABLE +/* Macro to log the Data */ +#define AOCL_DTL_LOG(LogLevel, Message) \ + DTL_Trace(LogLevel, \ + TRACE_TYPE_LOG, \ + __FILE__, \ + __FUNCTION__, \ + __LINE__, \ + Message); +#else +/* Dummy macro definition if the AOCL_DTL_LOG_ENABLE macro is not enabled */ +#define AOCL_DTL_LOG(LogLevel, Message) +#endif + +/* Macro to initialize the prerequisite for debuging */ +#ifdef AOCL_DTL_INITIALIZE_ENABLE +#define AOCL_DTL_INITIALIZE(CURRENT_LOG_LEVEL) \ + DTL_Initialize(CURRENT_LOG_LEVEL); +#else +/* Dummy macro definition if the AOCL_DTL_INITIALIZE macro is not enabled */ +#define AOCL_DTL_INITIALIZE(CURRENT_LOG_LEVEL) +#endif + +/* Macro for uninitializing the prerequisite */ +#ifdef AOCL_DTL_INITIALIZE_ENABLE +#define AOCL_DTL_UNINITIALIZE() \ + DTL_Uninitialize(); +#else +/* Dummy macro definition if the AOCL_DTL_INITIALIZE macro is not enabled */ +#define AOCL_DTL_UNINITIALIZE() +#endif + +#ifdef AOCL_DTL_INITIALIZE_ENABLE +/* Prototypes for initializing and uninitializing the debug functions */ +void DTL_Initialize( + uint32 ui32CurrentLogLevel); +void DTL_Uninitialize(void); +#endif + +#if (AOCL_DTL_TRACE_ENABLE || AOCL_DTL_LOG_ENABLE) +/* Debug trace Function protoypes */ +void DTL_Trace( + uint8 ui8LogLevel, + uint8 ui8LogType, + const int8 *pi8FileName, + const int8 *pi8FunctionName, + uint32 ui32LineNumber, + const int8 *pi8Message); + +#endif + +#if AOCL_DTL_DUMP_ENABLE +/* Function Prototype for dumping the data */ +void DTL_DumpData( + uint8 ui8LogLevel, + void *pvBuffer, + uint32 ui32BufferSize, + uint8 ui8DataType, + int8 *pi8Message, + int8 i8OutputType); +#endif + +#endif /* _AOCLDTL_H_ */ + +/* --------------- End of aocldtl.h ----------------- */ diff --git a/aocl_dtl/aocldtlcf.h b/aocl_dtl/aocldtlcf.h new file mode 100644 index 000000000..c0ebb6c7d --- /dev/null +++ b/aocl_dtl/aocldtlcf.h @@ -0,0 +1,61 @@ +/*=================================================================== + * File Name : aocldtlcf.h + * + * Description : This is configuration file for debug and trace + * libaray, all debug features (except auto trace) + * can be enabled/disabled in this file. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#ifndef _AOCLDTLCF_H_ +#define _AOCLDTLCF_H_ + +/* Macro for tracing the log If the user wants to enable tracing he has to + enable this macro by making it to 1 else 0 */ +#define AOCL_DTL_TRACE_ENABLE 1 + +/* Macro for dumping the log If the user wants to enable dumping he has to + enable this macro by making it to 1 else 0 */ +#define AOCL_DTL_DUMP_ENABLE 1 + +/* Macro for logging the logs If the user wants to enable loging information he + has to enable this macro by making it to 1 else 0 */ +#define AOCL_DTL_LOG_ENABLE 1 + +#define AOCL_DTL_TRACE_FILE "aocldtl_trace.wri" +#define AOCL_DTL_AUTO_TRACE_FILE "aocldtl_auto_trace.wri" +#define AOCL_DTL_LOG_FILE "aocldtl_log.wri" + +/* The use can use below three macros for different data type while dumping data + * or specify the size of data type in bytes macro for character data type */ +#define AOCL_CHAR_DATA_TYPE (1) + +/* macro for short data type */ +#define AOCL_UINT16_DATA_TYPE (2) + +/* macro for String data type */ +#define AOCL_STRING_DATA_TYPE (3) + +/* macro for uint32 data type */ +#define AOCL_UINT32_DATA_TYPE (4) + +/* macro for printing Hex values */ +#define AOCL_LOG_HEX_VALUE ('x') + +/* macro for printing Decimal values */ +#define AOCL_LOG_DECIMAL_VALUE ('d') + +/* user has to explicitly use the below macros to identify + ciriticality of the logged message */ +#define AOCL_DTL_LEVEL_ALL (6) +#define AOCL_DTL_LEVEL_VERBOSE (5) +#define AOCL_DTL_LEVEL_INFO (4) +#define AOCL_DTL_LEVEL_MINOR (3) +#define AOCL_DTL_LEVEL_MAJOR (2) +#define AOCL_DTL_LEVEL_CRITICAL (1) + +#endif /* _AOCLDTLCF_H_ */ + +/* --------------- End of aocldtlcf.h ----------------- */ diff --git a/aocl_dtl/aoclfal.c b/aocl_dtl/aoclfal.c new file mode 100644 index 000000000..a317e69cb --- /dev/null +++ b/aocl_dtl/aoclfal.c @@ -0,0 +1,265 @@ +/*=================================================================== + * File Name : aoclfal.c + * + * Description : Platform/os independed file handling API's + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#include "aocltpdef.h" +#include "aocldtl.h" +#include "aoclfal.h" + + + +/* Disable instrumentation for following function, since they are called from + * Auto Generated execution trace handlers. */ + +/* The FAL function declaration */ +int32 AOCL_FAL_Close( + AOCL_FAL_FILE *fpFilePointer) __attribute__((no_instrument_function)); + +int32 AOCL_FAL_Error( + AOCL_FAL_FILE *fpFilePointer) __attribute__((no_instrument_function)); + +AOCL_FAL_FILE *AOCL_FAL_Open( + const int8 *pchFileName, + const int8 *pchMode) __attribute__((no_instrument_function)); + +int32 AOCL_FAL_Read( + void *pvBuffer, + int32 i32Size, + int32 i32Count, + AOCL_FAL_FILE *fpFilePointer) __attribute__((no_instrument_function)); + +int32 AOCL_FAL_Write( + const void *pvBuffer, + int32 i32Size, + int32 iCount, + AOCL_FAL_FILE *fpFilePointer) __attribute__((no_instrument_function)); + +/*============================================================================= +* Function Name : AOCL_FAL_Open +* Description : Used for opening a file specified by name +* Input Parameter(s) : int8 *pchFileName - Stores the file name (path) +* int8 *pchMode - Specify the mode for opening file +* Output Parameter(s) : None +* Return parameter(s) : AOCL_FAL_FILE - If the file is opened successfully +* NULL - If there is any error while opening file +*============================================================================*/ +AOCL_FAL_FILE *AOCL_FAL_Open( + const int8 *pchFileName, + const int8 *pchMode) +{ + AOCL_FAL_FILE *fpFileOpen = NULL; + /* Open the file with provided by specified path and mode in which it should + be opened. Refer to FILE I/O operation help for getting mode types */ + fpFileOpen = fopen(pchFileName, pchMode); + /* If the file is not opened then NULL value should be returned */ + if (NULL == fpFileOpen) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Cannot open file: AOCL_FAL_Open()"); + } + return fpFileOpen; +} /* end of AOCL_FAL_Open */ + +/*============================================================================= +* Function Name : AOCL_FAL_Close +* Description : Used for closing a file specified by file pointer +* Input Parameter(s) : AOCL_FAL_FILE *fpFilePointer - File pointer +* Output Parameter(s) : None +* Return parameter(s) : 0 - If the file is closed successfully +* AOCL_FAL_CLOSE_ERROR - For any error while closing file +* +*============================================================================*/ +int32 AOCL_FAL_Close( + AOCL_FAL_FILE *fpFilePointer) +{ + /* Return value for the file close */ + int32 i32RetVal; + i32RetVal = AOCL_FAL_CLOSE_ERROR; + + /* Check whether the file pointer passed is valid or not */ + if (NULL == fpFilePointer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Can not close file: AOCL_FAL_Close()"); + return i32RetVal; + } + + /* Close the file using the FILE pointer passed */ + i32RetVal = fclose(fpFilePointer); + + /* If the return value is non zero then it indicates an error */ + if (i32RetVal) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, + "Can't close file, Invalid file pointer passed"); + return i32RetVal; + } + + /* On successful closing of the file, function should return 0 */ + return i32RetVal; + +} /* End of AOCL_FAL_Close */ + +/*============================================================================= +* Function Name : AOCL_FAL_Read +* Description : Used for reading a file specified by file pointer. +* This function reads the specified number of bytes +* from the file into the buffer specified. The bytes +* read are returned by this function. +* Input Parameter(s) : int32 i32Size - Item size in bytes +* int32 i32Count - Maximum number of items to be read +* AOCL_FAL_FILE *fpFilePointer - File ptr to read from +* Output Parameter(s) : void *pvBuffer - Storage location of data +* Return parameter(s) : i32RetVal - Number of bytes read if successful +* AOCL_FAL_READ_ERROR - In case of error while reading +*============================================================================*/ +int32 AOCL_FAL_Read( + void *pvBuffer, + int32 i32Size, + int32 i32Count, + AOCL_FAL_FILE *fpFilePointer) +{ + /* Return value for the file read */ + int32 i32RetVal; + i32RetVal = AOCL_FAL_READ_ERROR; + + /* Check pointer used for pointing the storage location data is valid */ + if (NULL == pvBuffer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, + "Can not read the file, Buffer pointer is NULL"); + return i32RetVal; + } + + /* Check whether file pointer passed is valid */ + if (NULL == fpFilePointer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, + "Can not read the file, Buffer pointer is NULL"); + return i32RetVal; + } + + /* Read the file using file pointer */ + i32RetVal = fread(pvBuffer, i32Size, i32Count, fpFilePointer); + + if (i32RetVal != i32Count) + { + /* Check whether this is an end of file The AOCL_FAL_Error() will return + non-zero value to indicate an error */ + if (AOCL_FAL_Error(fpFilePointer)) /* AOCL_FAL_EndOfFile (fpFilePointer) */ + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, + "There is an error condition while file read"); + i32RetVal = AOCL_FAL_READ_ERROR; + } + /* This is condition where file read has encountered an end of file */ + else + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "End of file..."); + } + } + + /* The number of bytes read by the file read operation. + * This value may be less than the actual count, due to end of file + * or an error while reading the file */ + return i32RetVal; + +} /* End of AOCL_FAL_Read */ + +/*============================================================================= +* Function Name : AOCL_FAL_Write +* Description : Used for writing data to a file specified by file +* pointer. The number of bytes written to file are +* written by this function. +* Input Parameter(s) : const void *pvBuffer - Pointer to data location from +* where the data to be copied + int32 i32Size - Item size in bytes +* int32 i32Count - Maximum number of items to be +* written +* AOCL_FAL_FILE *fpFilePointer - File pointer to write to +* Output Parameter(s) : None +* Return parameter(s) : i32RetVal - Number of bytes written if successful +* AOCL_FAL_WRITE_ERROR - In case of error while writing +*============================================================================*/ +int32 AOCL_FAL_Write( + const void *pvBuffer, + int32 i32Size, + int32 iCount, + AOCL_FAL_FILE *fpFilePointer) +{ + /* Return value for write operation */ + int32 i32RetVal; + i32RetVal = AOCL_FAL_WRITE_ERROR; + /* Check pointer used for pointing the storage location data is valid */ + if (NULL == pvBuffer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Can not perform file write"); + return i32RetVal; + } + + /* Check whether the file pointer passed is valid or not */ + if (NULL == fpFilePointer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Can not perform file write"); + return i32RetVal; + } + + /* Write into the file specified by the file pointer */ + i32RetVal = fwrite(pvBuffer, i32Size, iCount, fpFilePointer); + + /* If the number of bytes written into the file are less than specified + * bytes then it is an error while file writing */ + if (i32RetVal != iCount) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "File write operation error"); + i32RetVal = AOCL_FAL_WRITE_ERROR; + } + + /* The return value of the file write operation */ + return i32RetVal; + +} /* End of AOCL_FAL_Write */ + +/*============================================================================= +* Function Name : AOCL_FAL_Error +* Description : Used for testing an error on the file specified +* Input Parameter(s) : AOCL_FAL_FILE *fpFilePointer - File pointer +* Output Parameter(s) : None +* Return parameter(s) : non-zero - Indicates an end of file +* 0 - Indicates that function is successful +* non-zero - Indicates that there is some error +* AOCL_FAL_ERROR - Indicates error during the operation +*============================================================================*/ +int32 AOCL_FAL_Error( + AOCL_FAL_FILE *fpFilePointer) +{ + /* Used for storing the return value for ferror function */ + int32 i32RetVal; + i32RetVal = AOCL_FAL_FERROR; + + /* Check whether the file pointer is NULL */ + if (NULL == fpFilePointer) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Invalid file pointer is passed"); + return i32RetVal; + } + + /* Call the ferror function to get an error on the file */ + i32RetVal = ferror(fpFilePointer); + + /* Check for the return value, it non-zero there is an error */ + if (i32RetVal) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "The file has some error"); + i32RetVal = AOCL_FAL_FERROR; + } + + /* In case of success, this function should return 0 */ + return i32RetVal; + +} /* End of AOCL_FAL_Error */ + +/* ------------------- End of aoclfal.c ----------------------- */ diff --git a/aocl_dtl/aoclfal.h b/aocl_dtl/aoclfal.h new file mode 100644 index 000000000..9b8074528 --- /dev/null +++ b/aocl_dtl/aoclfal.h @@ -0,0 +1,50 @@ +/*=================================================================== + * File Name : aoclfal.h + * + * Description : Interfaces for platform/os independed file + * handling API's + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#ifndef _AOCL_FAL_H_ +#define _AOCL_FAL_H_ + +/* The possible error values of FAL */ +#define AOCL_FAL_SUCCESS 0 +#define AOCL_FAL_CLOSE_ERROR -1 +#define AOCL_FAL_READ_ERROR -2 +#define AOCL_FAL_WRITE_ERROR -3 +#define AOCL_FAL_EOF_ERROR -6 +#define AOCL_FAL_FERROR -7 + +/* The type definition for FILE */ +#define AOCL_FAL_FILE FILE + +/* The FAL function declaration */ +int32 AOCL_FAL_Close( + AOCL_FAL_FILE *fpFilePointer); + +int32 AOCL_FAL_Error( + AOCL_FAL_FILE *fpFilePointer); + +AOCL_FAL_FILE *AOCL_FAL_Open( + const int8 *pchFileName, + const int8 *pchMode); + +int32 AOCL_FAL_Read( + void *pvBuffer, + int32 i32Size, + int32 i32Count, + AOCL_FAL_FILE *fpFilePointer); + +int32 AOCL_FAL_Write( + const void *pvBuffer, + int32 i32Size, + int32 iCount, + AOCL_FAL_FILE *fpFilePointer); + +#endif /* _AOCL_FAL_H_ */ + +/* --------------- End of aoclfal.h ----------------- */ diff --git a/aocl_dtl/aoclflist.c b/aocl_dtl/aoclflist.c new file mode 100644 index 000000000..227347746 --- /dev/null +++ b/aocl_dtl/aoclflist.c @@ -0,0 +1,150 @@ +#include "aocltpdef.h" +#include "aocldtl.h" +#include "aoclfal.h" +#include "aoclflist.h" +#include "aoclos.h" + + +/* Disable instrumentation for following function, since they are called from + * Auto Generated execution trace handlers. */ +Bool AOCL_FLIST_IsEmpty( + AOCL_FLIST_Node *plist) __attribute__((no_instrument_function)); + +AOCL_FAL_FILE *AOCL_FLIST_GetFile( + AOCL_FLIST_Node *plist, + AOCL_TID tid) __attribute__((no_instrument_function)); + +AOCL_FAL_FILE *AOCL_FLIST_AddFile( + const int8 *pchFilePrefix, + AOCL_FLIST_Node **plist, + AOCL_TID tid) __attribute__((no_instrument_function)); + +void AOCL_FLIST_CloseFile( + AOCL_FLIST_Node *plist, + AOCL_TID tid) __attribute__((no_instrument_function)); + +void AOCL_FLIST_CloseAll( + AOCL_FLIST_Node *plist) __attribute__((no_instrument_function)); + + + +Bool AOCL_FLIST_IsEmpty(AOCL_FLIST_Node *plist) +{ + return (plist == NULL); + +} /* AOCL_FLIST_IsEmpty */ + +AOCL_FAL_FILE *AOCL_FLIST_GetFile(AOCL_FLIST_Node *plist, AOCL_TID tid) +{ + AOCL_FLIST_Node *temp; + + if (AOCL_FLIST_IsEmpty(plist) == 1) + { + return NULL; + } + + temp = plist; + + /* if list is not empty search for the file handle in all nodes */ + while (temp != NULL) + { + if (temp->tid == tid) + { + if (temp->fp == NULL) + { + AOCL_DEBUGPRINT("File associated with this thread id %d does not exists or closed", tid); + } + return temp->fp; + } + temp = temp->pNext; + } + + return NULL; + +} /* AOCL_FLIST_GetFile */ + +AOCL_FAL_FILE *AOCL_FLIST_AddFile(const int8 *pchFilePrefix, AOCL_FLIST_Node **plist, AOCL_TID tid) +{ + AOCL_FLIST_Node *newNode = NULL, *temp = NULL; + AOCL_FAL_FILE *file = NULL; + int8 pchFileName[40]; + + /* We don't want duplicates so we will check if the file already opened for this thread */ + file = AOCL_FLIST_GetFile(*plist, tid); + if (file != NULL) + { + AOCL_DEBUGPRINT("Open file alread exits for this key."); + return file; + } + + /* We don't have exiting file, lets try to open new one */ + sprintf(pchFileName, "%d_%s", tid, pchFilePrefix); + + file = AOCL_FAL_Open(pchFileName, "wb"); + if (file == NULL) + { + return NULL; + } + + /* Now allocate new node as we are sure we will need it */ + newNode = AOCL_malloc(sizeof(AOCL_FLIST_Node)); + if (newNode == NULL) + { + AOCL_FAL_Close(file); + AOCL_DEBUGPRINT("Out of memory while opening new log file"); + return NULL; + } + + newNode->pNext = NULL; + newNode->tid = tid; + newNode->fp = file; + + if (AOCL_FLIST_IsEmpty(*plist) == 1) + { + *plist = newNode; + } + else + { + /* go to the end of the list */ + for (temp = *plist; temp->pNext != NULL; temp = temp->pNext) + ; + + temp->pNext = newNode; + } + + AOCL_DEBUGPRINT("Created file for tid = %d", tid); + return newNode->fp; + +} /* AOCL_FLIST_AddFile */ + +void AOCL_FLIST_CloseFile(AOCL_FLIST_Node *plist, AOCL_TID tid) +{ + AOCL_FAL_FILE *pfile = AOCL_FLIST_GetFile(plist, tid); + AOCL_FAL_Close(pfile); + + return; + +} /* AOCL_FLIST_CloseFile */ + +void AOCL_FLIST_CloseAll(AOCL_FLIST_Node *plist) +{ + + AOCL_FLIST_Node *temp; + + if (AOCL_FLIST_IsEmpty(plist) == 1) + { + return; + } + + temp = plist; + + /* if list is not iterate over all nodes and close the assocaited files*/ + while (temp != NULL) + { + AOCL_FAL_Close(temp->fp); + temp = temp->pNext; + } + +} /* AOCL_FLIST_CloseAll */ + +/* ------------------- End of aoclflist.c ----------------------- */ diff --git a/aocl_dtl/aoclflist.h b/aocl_dtl/aoclflist.h new file mode 100644 index 000000000..849713bb0 --- /dev/null +++ b/aocl_dtl/aoclflist.h @@ -0,0 +1,46 @@ +/*=================================================================== + * File Name : aoclflist.h + * + * Description : Linked list of open files assocaited with + * each thread. This is used to log the deta + * to correct file as per the current thread id. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#ifndef _AOCL_FLIST_H_ +#define _AOCL_FLIST_H_ + +#include "aocltpdef.h" +#include "aoclfal.h" + +typedef struct AOCL_FLIST_Node_t +{ + AOCL_TID tid; + AOCL_FAL_FILE *fp; + struct AOCL_FLIST_Node_t *pNext; +} AOCL_FLIST_Node; + +Bool AOCL_FLIST_IsEmpty( + AOCL_FLIST_Node *plist); + +AOCL_FAL_FILE *AOCL_FLIST_GetFile( + AOCL_FLIST_Node *plist, + AOCL_TID tid); + +AOCL_FAL_FILE *AOCL_FLIST_AddFile( + const int8 *pchFilePrefix, + AOCL_FLIST_Node **plist, + AOCL_TID tid); + +void AOCL_FLIST_CloseFile( + AOCL_FLIST_Node *plist, + AOCL_TID tid); + +void AOCL_FLIST_CloseAll( + AOCL_FLIST_Node *plist); + +#endif /* _AOCL_FLIST_H_ */ + +/* --------------- End of aoclfist.h ----------------- */ diff --git a/aocl_dtl/aoclos.c b/aocl_dtl/aoclos.c new file mode 100644 index 000000000..e1feb1105 --- /dev/null +++ b/aocl_dtl/aoclos.c @@ -0,0 +1,73 @@ +/*=================================================================== + * File Name : aoclos.c + * + * Description : Abstraction for os services used by DTL. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ +#include "aocltpdef.h" +#include "aocldtl.h" +#include "aoclfal.h" +#include "aocldtlcf.h" + +#if defined(__linux__) +#include +#include +#endif + +#if defined(__linux__) + +/* + Disable intrumentation for these functions as they will also be + called from compiler generated instumation code to trace + function execution. + + It needs to be part of declration in the C file so can't be + moved to header file. + +*/ + +uint32 AOCL_gettid(void) __attribute__((no_instrument_function)); +uint64 AOCL_getTimestamp(void) __attribute__((no_instrument_function)); + +uint32 AOCL_gettid(void) +{ + return syscall(__NR_gettid); +} + +uint64 AOCL_getTimestamp(void) +{ + struct timespec tms; + + /* The C11 way */ + if (clock_gettime(CLOCK_REALTIME, &tms)) + { + return -1; + } + + /* seconds, multiplied with 1 million */ + uint64 micros = tms.tv_sec * 1000000; + /* Add full microseconds */ + micros += tms.tv_nsec / 1000; + /* round up if necessary */ + if (tms.tv_nsec % 1000 >= 500) + { + ++micros; + } + return micros; +} + +#else /* Non linux support */ +uint32 AOCL_gettid(void) +{ + /* stub for other os's */ + return 0; +} + +uint64 AOCL_getTimestamp(void) +{ + /* stub for other os's */ + return 0; +} +#endif diff --git a/aocl_dtl/aoclos.h b/aocl_dtl/aoclos.h new file mode 100644 index 000000000..187654c38 --- /dev/null +++ b/aocl_dtl/aoclos.h @@ -0,0 +1,27 @@ +/*=================================================================== + * File Name : aoclos.c + * + * Description : Abstraction for os services used by DTL. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#ifndef _AOCL_OS_H_ +#define _AOCL_OS_H_ + +#include "aocltpdef.h" +#include "malloc.h" + +/* The OS Services function declaration */ + +/* Alias for memory mangement functions. */ +#define AOCL_malloc malloc +#define AOCL_free free + +uint32 AOCL_gettid(void); +uint64 AOCL_getTimestamp(void); + +#endif /* _AOCL_OS_H_ */ + +/* --------------- End of aoclOS.h ----------------- */ diff --git a/aocl_dtl/aocltpdef.h b/aocl_dtl/aocltpdef.h new file mode 100644 index 000000000..c97ce7c92 --- /dev/null +++ b/aocl_dtl/aocltpdef.h @@ -0,0 +1,38 @@ + +/*=================================================================== + * File Name : aocltpdef.h + * + * Description : Abstraction for various datatypes used by DTL. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ +#ifndef AOCL_TYPEDEF_H_ +#define AOCL_TYPEDEF_H_ + +#include +#include +#include +#include +#include +#include + +typedef double Double; +typedef float Float; +typedef void Void; +typedef unsigned char uint8; +typedef unsigned short int uint16; +typedef unsigned int uint32; +typedef unsigned long uint64; +typedef uint8 *STRING; +typedef unsigned char Bool; +typedef char int8; +typedef signed long int int32; +typedef short int int16; + +typedef Void *AOCL_HANDLE; +typedef pid_t AOCL_TID; + +#endif /*AOCL_TYPEDEF_H_ */ + +/* --------------- End of aocltpdef.h ----------------- */ diff --git a/aocl_dtl/etrace_decoder.py b/aocl_dtl/etrace_decoder.py new file mode 100755 index 000000000..8fbeb810b --- /dev/null +++ b/aocl_dtl/etrace_decoder.py @@ -0,0 +1,175 @@ +#!/usr/bin/python + +""" + + BLIS + An object-based framework for developing high-performance BLAS-like + libraries. + + Copyright (C) 2014, The University of Texas at Austin + Copyright (C) 2018 - 2019, Advanced Micro Devices, Inc. + + 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. + - Neither the name(s) of the copyright holder(s) nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" + +import argparse +import subprocess +import re +import os + +binary_filename = "" +trace_filename = "" +missing_symbols = 0 +call_only = False +lookup = {} + + +def check_args(): + global binary_filename, call_only, trace_filename + parser = argparse.ArgumentParser(description='Decoder for BLIS execution trace. '\ + "Before running this utility ensure that BLIS library is built with execution trace enabled. " + "Run the application to create the trace data, after that only run this decoder") + parser.add_argument("--rawfile", required=True, type=str, help="Path to auto trace file generated by application") + parser.add_argument("--binary", required=True, type=str, help="Path to application binary") + parser.add_argument("--calls", action="store_true", help="Display only calls (no returns)") + + args = parser.parse_args() + + binary_filename = args.binary + trace_filename = args.rawfile + call_only = args.calls + +def check_files(): + binary_path = os.path.join(os.getcwd(), binary_filename) + trace_path = os.path.join(os.getcwd(), trace_filename) + + if not os.path.isfile(binary_path): + print ("\nBinary %s not found" % binary_path) + exit() + + if not os.path.isfile(trace_path): + print ("\nExecutation trace data (file blis.etrace) not found in current dirctory \ + \nPlease check the directory and ensure that application is built and ran \ + \nwith execution traces enabled.") + exit() + + + binary_mtime = os.path.getmtime(binary_path) + trace_mtime = os.path.getmtime(trace_path) + + if binary_mtime > trace_mtime: + print ("\n************************************************************************") + print ("\n* WARNING: Binary is latest than trace file, trace data may not match. *") + print ("\n************************************************************************") + + print ("Using binary file: %s" % binary_path) + print ("Using trace file: %s" % trace_path) + + +def create_symbol_table_lookup(): + temp = subprocess.Popen(["objdump", "-t" , binary_filename], stdout = subprocess.PIPE) + + output = str(temp.communicate()) + + output = output.split('\\n') + regex_lookup = re.compile(r'.text') + + for line in range(len(output)): + count = regex_lookup.findall(output[line]) + if len(count) > 0: + current_line = output[line].split() + key, value = int(current_line[0], 16), current_line[4] + lookup[key] = value + +def decode_symbols_from_trace(): + global missing_symbols + raw_contents = [] + with open(trace_filename, "r") as f: + raw_contents = f.read() + + raw_contents = raw_contents.split("\n") + + level = [] + first_timestamp = 0 + last_timestamp = 0 + + + for line in range(len(raw_contents)): + current_line = raw_contents[line].split(":") + if len(current_line) != 4: + continue + + print_string = current_line[0] + " " + print_string += current_line[2] + + if current_line[2] == "+": + last_level = "+" + level.append(1) + else: + last_level = "-" + if len(level) > 0: + level.pop() + + if last_level == "-": + for i in range(len(level) + 1) : + print_string += "." + else: + for i in range(len(level)) : + print_string += "." + + try: + print_string += lookup[int(current_line[3], 16)] + except KeyError: + missing_symbols += 1 + print_string += current_line[3] + + if line == 1: + first_timestamp = int(current_line[1]) + print_string += "(+0us)" + else: + delta_last = int(current_line[1]) - last_timestamp + delta_total = int(current_line[1]) - first_timestamp + print_string += "(+" + str(delta_last) + "us, " + str(delta_total) + "us)" + + + if last_level == "-" and call_only: + continue + else: + last_timestamp = int(current_line[1]) + + print (print_string) + +if __name__ == "__main__": + + check_args() + check_files() + create_symbol_table_lookup() + decode_symbols_from_trace() + + if missing_symbols > 0: + print("\nWARNING: Some symbols are not found, this can happen if binary is not matching \ + \nor symbols are stripped from it.") + diff --git a/aocl_dtl/test_dtl.c b/aocl_dtl/test_dtl.c new file mode 100644 index 000000000..00b385022 --- /dev/null +++ b/aocl_dtl/test_dtl.c @@ -0,0 +1,101 @@ +/*=================================================================== + * File Name : test_dtl.c + * + * Description : Unit test cases for dtl. + * + * Copyright (C) 2020, Advanced Micro Devices, Inc + * + *==================================================================*/ + +#if 0 // Disable this for normal build. + +#include "aocltpdef.h" +#include "aocldtl.h" + +int aocl_allocate(double**A, double** B, double** C, int N) +{ + AOCL_DTL_TRACE_ENTRY(AOCL_DTL_LEVEL_INFO, " aocl_allocate()"); + + *A = (double*)malloc(sizeof(double) * N); + if (*A == NULL) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Error allocating memory to A"); + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, " aocl_allocate()"); + return 1; + } + + *B = (double*)malloc(sizeof(double) * N); + if (*B == NULL) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Error allocating memory to B"); + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, " aocl_allocate()"); + return 1; + } + + *C = (double*)malloc(sizeof(double) * N); + if (*C == NULL) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Error allocating memory to C"); + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, " aocl_allocate()"); + return 1; + } + + for (int i = 0; i < N; i++) + { + (*A)[i] = (double)((i + 1) * 1.0); + (*B)[i] = (double)((i - 1) * 1.0); + (*C)[i] = (double)((i) * 1.0); + } + + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, " aocl_allocate()"); + return 0; +} + +void sumV(double* A, double* B, double* C, int N) +{ + AOCL_DTL_TRACE_ENTRY(AOCL_DTL_LEVEL_INFO, "sumV()"); + if ((A == NULL) || (B == NULL) || (C == NULL)) + { + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Invalid Pointers"); + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, " sumV()"); + return; + } + for (int i = 0; i < N; i++) + { + C[i] += A[i] + B[i]; + } + + AOCL_DTL_TRACE_EXIT(AOCL_DTL_LEVEL_INFO, "sumV()"); +} + +int main(void) +{ + int status = 0; + double* A = NULL; + double* B = NULL; + double* C = NULL; + + printf("Initializing\n"); + AOCL_DTL_INITIALIZE(AOCL_DTL_LEVEL_ALL); + + AOCL_DTL_TRACE_ENTRY(AOCL_TRACE_LEVEL_1, "Main function()"); + + status = aocl_allocate(&A, &B, &C, 120); + if (status != 0) + { + printf("Error allocating memory\n"); + + AOCL_DTL_LOG(AOCL_DTL_LEVEL_MAJOR, "Error in function aocl_allocate()"); + AOCL_DTL_TRACE_EXIT(AOCL_TRACE_LEVEL_1, "Main function()"); + AOCL_DTL_UNINITIALIZE(); + exit(1); + } + + sumV(A, B, C, 120); + + AOCL_DTL_TRACE_EXIT(AOCL_TRACE_LEVEL_1, "Main function()"); + AOCL_DTL_UNINITIALIZE(); + + return 0; +} +#endif \ No newline at end of file diff --git a/common.mk b/common.mk index dc1f6def3..e1ec24a29 100644 --- a/common.mk +++ b/common.mk @@ -143,6 +143,13 @@ get-frame-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ $(BUILD_SYMFLAGS) \ ) +get-aocldtl-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ + $(call get-noopt-cflags-for,$(1)) \ + $(BUILD_CPPFLAGS) \ + $(BUILD_SYMFLAGS) \ + ) + + get-kernel-cflags-for = $(strip $(call load-var-for,CKOPTFLAGS,$(1)) \ $(call load-var-for,CKVECFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ @@ -187,6 +194,7 @@ get-refinit-text-for = "('$(1)' CFLAGS for ref. kernel init)" get-refkern-text-for = "('$(1)' CFLAGS for ref. kernels)" get-config-text-for = "('$(1)' CFLAGS for config code)" get-frame-text-for = "('$(1)' CFLAGS for framework code)" +get-aocldtl-text-for = "('$(1)' CFLAGS for AOCL debug and trace code)" get-kernel-text-for = "('$(1)' CFLAGS for kernels)" get-sandbox-c99text-for = "('$(1)' CFLAGS for sandboxes)" get-sandbox-cxxtext-for = "('$(1)' CXXFLAGS for sandboxes)" @@ -285,6 +293,7 @@ FRAGMENT_MK := .fragment.mk BUILD_DIR := build CONFIG_DIR := config FRAME_DIR := frame +AOCLDTL_DIR := aocl_dtl REFKERN_DIR := ref_kernels KERNELS_DIR := kernels SANDBOX_DIR := sandbox @@ -306,6 +315,8 @@ KERNELS_SRC_SUFS := c s S FRAME_SRC_SUFS := c +AOCLDTL_SRC_SUFS := c + SANDBOX_C99_SUFS := c SANDBOX_CXX_SUFS := cc cpp cxx SANDBOX_SRC_SUFS := $(SANDBOX_C99_SUFS) $(SANDBOX_CXX_SUFS) @@ -313,16 +324,20 @@ SANDBOX_SRC_SUFS := $(SANDBOX_C99_SUFS) $(SANDBOX_CXX_SUFS) # Header suffixes. FRAME_HDR_SUFS := h +AOCLDTL_HDR_SUFS := h + SANDBOX_H99_SUFS := h SANDBOX_HXX_SUFS := hh hpp hxx SANDBOX_HDR_SUFS := $(SANDBOX_H99_SUFS) $(SANDBOX_HXX_SUFS) # Combine all header suffixes and remove duplicates via sort(). -ALL_HDR_SUFS := $(sort $(FRAME_HDR_SUFS) \ - $(SANDBOX_HDR_SUFS) ) +ALL_HDR_SUFS := $(sort $(FRAME_HDR_SUFS) \ + $(SANDBOX_HDR_SUFS) \ + $(AOCLDTL_HDR_SUFS)) -ALL_H99_SUFS := $(sort $(FRAME_HDR_SUFS) \ - $(SANDBOX_H99_SUFS) ) +ALL_H99_SUFS := $(sort $(FRAME_HDR_SUFS) \ + $(SANDBOX_H99_SUFS) \ + $(AOCLDTL_HDR_SUFS)) # The names of scripts that check output from the BLAS test drivers and # BLIS test suite. @@ -351,6 +366,7 @@ SHELL := bash # and optimized kernel code. CONFIG_PATH := $(DIST_PATH)/$(CONFIG_DIR) FRAME_PATH := $(DIST_PATH)/$(FRAME_DIR) +AOCLDTL_PATH := $(DIST_PATH)/$(AOCLDTL_DIR) REFKERN_PATH := $(DIST_PATH)/$(REFKERN_DIR) KERNELS_PATH := $(DIST_PATH)/$(KERNELS_DIR) SANDBOX_PATH := $(DIST_PATH)/$(SANDBOX_DIR) @@ -360,6 +376,7 @@ SANDBOX_PATH := $(DIST_PATH)/$(SANDBOX_DIR) # kernel code, and optimized kernel code. CONFIG_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(CONFIG_DIR) FRAME_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(FRAME_DIR) +AOCLDTL_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(AOCLDTL_DIR) REFKERN_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(REFKERN_DIR) KERNELS_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(KERNELS_DIR) SANDBOX_FRAG_PATH := ./obj/$(CONFIG_NAME)/$(SANDBOX_DIR) @@ -800,8 +817,6 @@ ENABLE_VERBOSE := no BLIS_ENABLE_TEST_OUTPUT := no endif - - # # --- Append OS-specific libraries to LDFLAGS ---------------------------------- # @@ -838,6 +853,7 @@ MK_CONFIG_SRC := MK_KERNELS_SRC := MK_REFKERN_SRC := MK_FRAME_SRC := +MK_AOCLDTL_SRC := MK_SANDBOX_SRC := # -- config -- @@ -887,6 +903,7 @@ PARENT_PATH := $(OBJ_DIR)/$(CONFIG_NAME) # reference kernels and portable framework. -include $(addsuffix /$(FRAGMENT_MK), $(REFKERN_FRAG_PATH)) -include $(addsuffix /$(FRAGMENT_MK), $(FRAME_FRAG_PATH)) +-include $(addsuffix /$(FRAGMENT_MK), $(AOCLDTL_FRAG_PATH)) # -- sandbox -- diff --git a/config/zen/make_defs.mk b/config/zen/make_defs.mk index f7f84aee2..21a9fcce7 100644 --- a/config/zen/make_defs.mk +++ b/config/zen/make_defs.mk @@ -52,6 +52,16 @@ else COPTFLAGS := -O3 endif + +# +# --- Enable ETRACE across the library if enabled ETRACE_ENABLE=[0,1] ----------------------- +# + +ifeq ($(ETRACE_ENABLE),1) +CDBGFLAGS += -pg -finstrument-functions -DAOCL_DTL_AUTO_TRACE_ENABLE +LDFLAGS += -ldl +endif + # Flags specific to optimized kernels. CKOPTFLAGS := $(COPTFLAGS) ifeq ($(CC_VENDOR),gcc) diff --git a/config/zen2/make_defs.mk b/config/zen2/make_defs.mk index d457037dd..5d3f11f67 100644 --- a/config/zen2/make_defs.mk +++ b/config/zen2/make_defs.mk @@ -61,8 +61,23 @@ endif ifeq ($(DEBUG_TYPE),noopt) COPTFLAGS := -O0 else +#frame pointers are needed to execution tracing +ifeq ($(ETRACE_ENABLE),1) +COPTFLAGS := -O3 +else COPTFLAGS := -O3 -fomit-frame-pointer endif +endif + + +# +# --- Enable ETRACE across the library if enabled ETRACE_ENABLE=[0,1] ----------------------- +# + +ifeq ($(ETRACE_ENABLE),1) +CDBGFLAGS += -pg -finstrument-functions -DAOCL_DTL_AUTO_TRACE_ENABLE +LDFLAGS += -ldl +endif # Flags specific to optimized kernels. CKOPTFLAGS := $(COPTFLAGS) diff --git a/configure b/configure index cffa4c62c..b8098ce5a 100755 --- a/configure +++ b/configure @@ -1844,6 +1844,10 @@ main() frame_dir='frame' frame_dirpath="${dist_path}/${frame_dir}" + # The root directory of the BLIS framework. + aocldtl_dir='aocl_dtl' + aocldtl_dirpath="${dist_path}/${aocldtl_dir}" + # The name of the sandbox directory. sandbox_dir='sandbox' sandbox_dirpath="${dist_path}/${sandbox_dir}" @@ -3199,12 +3203,17 @@ main() done + obj_aocldtl_dirpath="${base_obj_dirpath}/${aocldtl_dir}" + + echo "${script_name}: creating ${obj_aocldtl_dirpath}" + mkdir -p ${obj_aocldtl_dirpath} + + obj_frame_dirpath="${base_obj_dirpath}/${frame_dir}" echo "${script_name}: creating ${obj_frame_dirpath}" mkdir -p ${obj_frame_dirpath} - if [ -n "${sandbox_flag}" ]; then obj_sandbox_dirpath="${base_obj_dirpath}/${sandbox_dir}" @@ -3286,6 +3295,10 @@ main() echo "${script_name}: mirroring ${frame_dirpath} to ${obj_frame_dirpath}" ${mirror_tree_sh} ${frame_dirpath} ${obj_frame_dirpath} + # Mirror framework source tree to its object sub-directory. + echo "${script_name}: mirroring ${aocldtl_dirpath} to ${obj_aocldtl_dirpath}" + ${mirror_tree_sh} ${aocldtl_dirpath} ${obj_aocldtl_dirpath} + # Mirror the chosen sandbox source tree to its object sub-directory. if [ -n "${sandbox_flag}" ]; then @@ -3360,6 +3373,18 @@ main() ${gen_make_frags_dirpath}/suffix_list \ ${gen_make_frags_dirpath}/ignore_list + # Generate makefile fragments in the DTL directory. + echo "${script_name}: creating makefile fragments in ${obj_aocldtl_dirpath}" + ${gen_make_frags_sh} \ + -h -r -v0 \ + -o ${script_name} \ + -p 'AOCLDTL' \ + ${aocldtl_dirpath} \ + ${obj_aocldtl_dirpath} \ + ${gen_make_frags_dirpath}/fragment.mk \ + ${gen_make_frags_dirpath}/suffix_list \ + ${gen_make_frags_dirpath}/ignore_list + # Generate makefile fragments in the framework directory. echo "${script_name}: creating makefile fragments in ${obj_frame_dirpath}" ${gen_make_frags_sh} \ diff --git a/frame/base/bli_init.c b/frame/base/bli_init.c index a719b25f8..5baa55b21 100644 --- a/frame/base/bli_init.c +++ b/frame/base/bli_init.c @@ -74,6 +74,7 @@ void bli_finalize_auto( void ) void bli_init_apis( void ) { + AOCL_DTL_INITIALIZE(AOCL_DTL_LEVEL_ALL); // Initialize various sub-APIs. bli_gks_init(); bli_ind_init(); @@ -90,6 +91,7 @@ void bli_finalize_apis( void ) bli_thread_finalize(); bli_ind_finalize(); bli_gks_finalize(); + AOCL_DTL_UNINITIALIZE(); } // ----------------------------------------------------------------------------- diff --git a/frame/include/blis.h b/frame/include/blis.h index e51f0a5c3..4725ee83f 100644 --- a/frame/include/blis.h +++ b/frame/include/blis.h @@ -203,7 +203,8 @@ extern "C" { #include "bli_winsys.h" - +#include "aocldtl.h" + // End extern "C" construct block. #ifdef __cplusplus }