Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ tvm_option(INDEX_DEFAULT_I64 "Defaults the index datatype to int64" ON)
tvm_option(USE_LIBBACKTRACE "Build libbacktrace to supply linenumbers on stack traces" AUTO)
tvm_option(BUILD_STATIC_RUNTIME "Build static version of libtvm_runtime" OFF)
tvm_option(USE_PAPI "Use Performance Application Programming Interface (PAPI) to read performance counters" OFF)
tvm_option(USE_LIKWID "Use Likwid to read performance counters" OFF)
tvm_option(USE_GTEST "Use GoogleTest for C++ sanity tests" AUTO)
tvm_option(USE_CUSTOM_LOGGING "Use user-defined custom logging, tvm::runtime::detail::LogFatalImpl and tvm::runtime::detail::LogMessageImpl must be implemented" OFF)
tvm_option(USE_ALTERNATIVE_LINKER "Use 'mold' or 'lld' if found when invoking compiler to link artifact" AUTO)
Expand Down Expand Up @@ -554,6 +555,8 @@ include(cmake/modules/Logging.cmake)

include(cmake/modules/contrib/PAPI.cmake)

include(cmake/modules/contrib/Likwid.cmake)

if(USE_MICRO)
# NOTE: cmake doesn't track dependencies at the file level across subdirectories. For the
# Unix Makefiles generator, need to add these explicit target-level dependency)
Expand Down
2 changes: 2 additions & 0 deletions cmake/config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ set(BUILD_STATIC_RUNTIME OFF)
# - /path/to/folder/containing/: Path to folder containing papi.pc.
set(USE_PAPI OFF)

set(USE_LIKWID ON)

# Whether to use GoogleTest for C++ unit tests. When enabled, the generated
# build file (e.g. Makefile) will have a target "cpptest".
# Possible values:
Expand Down
7 changes: 7 additions & 0 deletions cmake/modules/contrib/Likwid.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
if (USE_LIKWID)
message(STATUS "Using Likwid library")
target_link_libraries(tvm_runtime_objs PRIVATE -llikwid)
target_link_libraries(tvm PRIVATE -llikwid)
target_link_libraries(tvm_runtime PRIVATE -llikwid)
target_sources(tvm_runtime_objs PRIVATE src/runtime/contrib/likwid/likwid.cc)
endif()
18 changes: 18 additions & 0 deletions include/tvm/runtime/contrib/likwid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef TVM_RUNTIME_CONTRIB_LIKWID_H_
#define TVM_RUNTIME_CONTRIB_LIKWID_H_

#include <tvm/runtime/container/array.h>
#include <tvm/runtime/container/map.h>
#include <tvm/runtime/profiling.h>

namespace tvm {
namespace runtime {
namespace profiling {

TVM_DLL MetricCollector CreateLikwidMetricCollector(Array<DeviceWrapper> devices);

} // namespace profiling
} // namespace runtime
} // namespace tvm

#endif // TVM_RUNTIME_CONTRIB_LIKWID_H_
11 changes: 11 additions & 0 deletions python/tvm/runtime/profiling/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,14 @@ def __init__(self, metric_names: Optional[Dict[Device, Sequence[str]]] = None):
for dev, names in metric_names.items():
wrapped[DeviceWrapper(dev)] = names
self.__init_handle_by_constructor__(_ffi_api.PAPIMetricCollector, wrapped)


# We only enable this class when TVM is build with Likwid support
if _ffi.get_global_func("runtime.profiling.LikwidMetricCollector", allow_missing=True) is not None:

@_ffi.register_object("runtime.profiling.LikwidMetricCollector")
class LikwidMetricCollector(MetricCollector):

def __init__(self, devices: Optional[Sequence[Device]] = None):
wrapped_devices = [DeviceWrapper(dev) for dev in devices]
self.__init_handle_by_constructor__(_ffi_api.LikwidMetricCollector, wrapped_devices)
134 changes: 134 additions & 0 deletions src/runtime/contrib/likwid/likwid.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include <likwid.h>
#include <tvm/runtime/contrib/likwid.h>

#include <string>
#include <vector>

#ifdef LIKWID_PERFMON
#include <likwid-marker.h>
#else
#define LIKWID_MARKER_INIT
#define LIKWID_MARKER_THREADINIT
#define LIKWID_MARKER_SWITCH
#define LIKWID_MARKER_REGISTER(regionTag)
#define LIKWID_MARKER_START(regionTag)
#define LIKWID_MARKER_STOP(regionTag)
#define LIKWID_MARKER_CLOSE
#define LIKWID_MARKER_GET(regionTag, nevents, events, time, count)
#endif

namespace tvm {
namespace runtime {
namespace profiling {


constexpr const char* REGION_NAME = "LikwidMetricCollector";


struct LikwidEventSetNode : public Object {

std::vector<double> start_values;
Device dev;

explicit LikwidEventSetNode(std::vector<double> start_values, Device dev)
: start_values(start_values), dev(dev) {}

static constexpr const char* _type_key = "LikwidEventSetNode";
TVM_DECLARE_FINAL_OBJECT_INFO(LikwidEventSetNode, Object);
};

struct LikwidMetricCollectorNode final : public MetricCollectorNode {
explicit LikwidMetricCollectorNode(Array<DeviceWrapper> devices) {
// Do nothing for now...
}

explicit LikwidMetricCollectorNode() {}

void Init(Array<DeviceWrapper> devices) override {
likwid_markerInit();
likwid_markerRegisterRegion(REGION_NAME);
likwid_markerStartRegion(REGION_NAME);
}

ObjectRef Start(Device device) override {
likwid_markerThreadInit();
int nevents = 20;
double events[20];
double time;
int count;
_read_event_counts(&nevents, events, &time, &count);
std::vector<double> start_values(events, events + nevents * sizeof(double));
return ObjectRef(make_object<LikwidEventSetNode>(start_values, device));
}

Map<String, ObjectRef> Stop(ObjectRef object) override {
const LikwidEventSetNode* event_set_node = object.as<LikwidEventSetNode>();
int nevents = 20;
double events[20];
double time;
int count;
_read_event_counts(&nevents, events, &time, &count);
std::vector<double> end_values(events, events + nevents * sizeof(double));
std::unordered_map<String, ObjectRef> reported_metrics;
for (size_t i{}; i < nevents; ++i) {
if (end_values[i] < event_set_node->start_values[i]) {
LOG(WARNING) << "Detected overflow while reading performance counter, setting value to -1";
reported_metrics[String(std::to_string(i))] =
ObjectRef(make_object<CountNode>(-1));
} else {
reported_metrics[String(std::to_string(i))] =
ObjectRef(make_object<CountNode>(end_values[i] - event_set_node->start_values[i]));
}
}
return reported_metrics;
}

~LikwidMetricCollectorNode() final {
int res = likwid_markerStopRegion(REGION_NAME);
if (res < 0) {
LOG(ERROR) << "Could not stop marker region! Error code: " << res;
}
likwid_markerClose();
}

void _read_event_counts(int* nevents, double* events, double* time, int* count) {
int status = likwid_markerStopRegion(REGION_NAME);
if (status < 0) {
LOG(ERROR) << "Could not stop marker region! Error code: " << status;
}
likwid_markerGetRegion(REGION_NAME, nevents, events, time, count);
if (nevents == 0) {
LOG(WARNING) << "Event count is zero!";
}
status = likwid_markerStartRegion(REGION_NAME);
if (status < 0) {
LOG(ERROR) << "Could not start marker region! Error code: " << status;
}
}

static constexpr const char* _type_key = "runtime.profiling.LikwidMetricCollector";
TVM_DECLARE_FINAL_OBJECT_INFO(LikwidMetricCollectorNode, MetricCollectorNode);
};


class LikwidMetricCollector : public MetricCollector {
public:
explicit LikwidMetricCollector(Array<DeviceWrapper> devices) {
data_ = make_object<LikwidMetricCollectorNode>(devices);
}
TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(LikwidMetricCollector, MetricCollector,
LikwidMetricCollectorNode);
};


TVM_REGISTER_OBJECT_TYPE(LikwidEventSetNode);
TVM_REGISTER_OBJECT_TYPE(LikwidMetricCollectorNode);

TVM_REGISTER_GLOBAL("runtime.profiling.LikwidMetricCollector")
.set_body_typed([](Array<DeviceWrapper> devices) {
return LikwidMetricCollector(devices);
});

} // namespace profiling
} // namespace runtime
} // namespace tvm