Skip to content

Commit

Permalink
add a new metadata section in xclbin to support AIE profiling/debug (#…
Browse files Browse the repository at this point in the history
…8304)

* add a new metadata section in xclbin to support AIE profiling/debug

Signed-off-by: xvijaysri <[email protected]>

* added unit test for AIE TRACE METADATA

Signed-off-by: xvijaysri <[email protected]>

* fixed formatting issue

Signed-off-by: xvijaysri <[email protected]>

* addressed the review comments

Signed-off-by: xvijaysri <[email protected]>

---------

Signed-off-by: xvijaysri <[email protected]>
  • Loading branch information
xvijaysri authored Aug 5, 2024
1 parent c98e177 commit b491b38
Show file tree
Hide file tree
Showing 7 changed files with 748 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/runtime_src/core/include/xclbin.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ extern "C" {
AIE_PARTITION = 32,
IP_METADATA = 33,
AIE_RESOURCES_BIN = 34,
AIE_TRACE_METADATA = 35,
};

enum MEM_TYPE {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime_src/tools/xclbinutil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ if(NOT WIN32)
set(TEST_OPTIONS " --resource-dir ${CMAKE_CURRENT_SOURCE_DIR}/unittests/AieResourcesBin")
xrt_add_test("AieResourcesBin" "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/unittests/AieResourcesBin/SectionAieResourcesBin.py ${TEST_OPTIONS}")

# -- AIE TRACE METADATA Section
set(TEST_OPTIONS " --resource-dir ${CMAKE_CURRENT_SOURCE_DIR}/unittests/AieTraceMetadata")
xrt_add_test("AieTraceMetadata" "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/unittests/AieTraceMetadata/SectionAieTraceMetadata.py ${TEST_OPTIONS}")


endif()


Expand Down
82 changes: 82 additions & 0 deletions src/runtime_src/tools/xclbinutil/SectionAIETraceMetadata.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may
* not use this file except in compliance with the License. A copy of the
* License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

#include "SectionAIETraceMetadata.h"

#include "XclBinUtilities.h"
#include <boost/functional/factory.hpp>
#include <boost/property_tree/json_parser.hpp>

namespace XUtil = XclBinUtilities;

// Static Variables / Classes
// ----------------------------------------------------------------------------
SectionAIETraceMetadata::init SectionAIETraceMetadata::initializer;

SectionAIETraceMetadata::init::init()
{
auto sectionInfo = std::make_unique<SectionInfo>(AIE_TRACE_METADATA, "AIE_TRACE_METADATA", boost::factory<SectionAIETraceMetadata*>());

sectionInfo->supportedAddFormats.push_back(FormatType::json);
sectionInfo->supportedAddFormats.push_back(FormatType::raw);

sectionInfo->supportedDumpFormats.push_back(FormatType::json);
sectionInfo->supportedDumpFormats.push_back(FormatType::raw);

addSectionType(std::move(sectionInfo));
}

// ----------------------------------------------------------------------------

void
SectionAIETraceMetadata::marshalToJSON(char* _pDataSection,
unsigned int _sectionSize,
boost::property_tree::ptree& _ptree) const
{
XUtil::TRACE("");
XUtil::TRACE("Extracting: AIE_TRACE_METADATA");

std::vector<unsigned char> memBuffer(_sectionSize + 1); // Extra byte for "null terminate" char
memcpy((char*)memBuffer.data(), _pDataSection, _sectionSize);
memBuffer[_sectionSize] = '\0';

std::stringstream ss((char*)memBuffer.data());

// TODO: Catch the exception (if any) from this call and produce a nice message
XUtil::TRACE_BUF("AIE_TRACE_METADATA", (const char*)memBuffer.data(), _sectionSize + 1);
try {
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt);
boost::property_tree::ptree& buildMetaData = pt.get_child("aie_metadata");
_ptree.add_child("aie_trace_metadata", buildMetaData);
} catch (const std::exception& e) {
std::string msg("ERROR: Bad JSON format detected while marshaling AIE trace metadata (");
msg += e.what();
msg += ").";
throw std::runtime_error(msg);
}
}

void
SectionAIETraceMetadata::marshalFromJSON(const boost::property_tree::ptree& _ptSection,
std::ostringstream& _buf) const
{
XUtil::TRACE("AIE_TRACE_METADATA");
boost::property_tree::ptree ptWritable = _ptSection;
boost::property_tree::write_json(_buf, ptWritable, false);
}


37 changes: 37 additions & 0 deletions src/runtime_src/tools/xclbinutil/SectionAIETraceMetadata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may
* not use this file except in compliance with the License. A copy of the
* License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

#ifndef __SectionAIETraceMetadata_h_
#define __SectionAIETraceMetadata_h_

// ----------------------- I N C L U D E S -----------------------------------
#include "Section.h"

// ------ C L A S S : S e c t i o n A I E T r a c e M e t a d a t a ------------------
class SectionAIETraceMetadata : public Section {
protected:
void marshalToJSON(char* _pDataSection, unsigned int _sectionSize, boost::property_tree::ptree& _ptree) const override;
void marshalFromJSON(const boost::property_tree::ptree& _ptSection, std::ostringstream& _buf) const override;

private:
// Static initializer helper class
static class init {
public:
init();
} initializer;
};

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from argparse import RawDescriptionHelpFormatter
import argparse
import os
import subprocess
import json

# Start of our unit test
# -- main() -------------------------------------------------------------------
#
# The entry point to this script.
#
# Note: It is called at the end of this script so that the other functions
# and classes have been defined and the syntax validated
def main():
# -- Configure the argument parser
parser = argparse.ArgumentParser(formatter_class=RawDescriptionHelpFormatter, description='description:\n Unit test wrapper for the AIE TRACE METADATA section')
parser.add_argument('--resource-dir', nargs='?', default=".", help='directory containing data to be used by this unit test')
args = parser.parse_args()

# Validate that the resource directory is valid
if not os.path.exists(args.resource_dir):
raise Exception("Error: The resource-dir '" + args.resource_dir +"' does not exist")

if not os.path.isdir(args.resource_dir):
raise Exception("Error: The resource-dir '" + args.resource_dir +"' is not a directory")

# Prepare for testing
xclbinutil = "xclbinutil"

# Start the tests
print ("Starting test")

# ---------------------------------------------------------------------------

step = "1) Read in the AIE TRACE METADATA section"

inputJSON = os.path.join(args.resource_dir, "aie_trace_config.json")
outputXCLBIN = "output.xclbin"

cmd = [xclbinutil, "--add-section", "AIE_TRACE_METADATA:JSON:" + inputJSON, "--output", outputXCLBIN, "--force"]
execCmd(step, cmd)

# ---------------------------------------------------------------------------

step = "2) Validate the AIE_TRACE_METADATA section"

expectedJSON = os.path.join(args.resource_dir, "expected_aie_trace_config.json")
actualJSON = "actual_aie_trace_config.json"

cmd = [xclbinutil, "--input", outputXCLBIN, "--dump-section", "AIE_TRACE_METADATA:JSON:" + actualJSON, "--force"]
execCmd(step, cmd)
jsonFileCompare(actualJSON, expectedJSON)


# ---------------------------------------------------------------------------

# If the code gets this far, all is good.
return False

def jsonFileCompare(file1, file2):

if not os.path.isfile(file1):
raise Exception("Error: The following json file does not exist: '" + file1 +"'")

with open(file1) as f:
data1 = json.dumps(json.load(f), indent=2)

if not os.path.isfile(file2):
raise Exception("Error: The following json file does not exist: '" + file2 +"'")

with open(file2) as f:
data2 = json.dumps(json.load(f), indent=2)

if data1 != data2:
# Print out the contents of file 1
print ("\nFile1 : "+ file1)
print ("vvvvv")
print (data1)
print ("^^^^^")

# Print out the contents of file 1
print ("\nFile2 : "+ file2)
print ("vvvvv")
print (data2)
print ("^^^^^")

raise Exception("Error: The given files are not the same")

def testDivider():
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")


def execCmd(pretty_name, cmd):
testDivider()
print(pretty_name)
testDivider()
cmdLine = ' '.join(cmd)
print(cmdLine)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
o, e = proc.communicate()
print(o.decode('ascii'))
print(e.decode('ascii'))
errorCode = proc.returncode

if errorCode != 0:
raise Exception("Operation failed with the return code: " + str(errorCode))

# -- Start executing the script functions
if __name__ == '__main__':
try:
if main() == True:
print ("\nError(s) occurred.")
print("Test Status: FAILED")
exit(1)
except Exception as error:
print(repr(error))
print("Test Status: FAILED")
exit(1)


# If the code get this far then no errors occured
print("Test Status: PASSED")
exit(0)

Loading

0 comments on commit b491b38

Please sign in to comment.