Skip to content

Commit

Permalink
Adds unit tests for Python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
ilumsden committed Sep 10, 2024
1 parent 555661a commit e6b3ce2
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 31 deletions.
36 changes: 33 additions & 3 deletions bindings/python/instrumentation.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "instrumentation.h"
#include "variant.h"
#include <stdexcept>

namespace cali {
Expand All @@ -18,6 +19,31 @@ PythonAttribute::PythonAttribute(const char *name, cali_attr_type type,
}
}

PythonAttribute::PythonAttribute(const char *name, cali_attr_type type,
cali_attr_properties opt,
std::vector<PythonAttribute &> &meta_attrs,
std::vector<PythonVariant &> &meta_vals) {
if (meta_attrs.size() != meta_vals.size()) {
throw std::runtime_error(
"'meta_attrs' and 'meta_vals' must be same length");
}
size_t num_meta_elems = meta_attrs.size();
cali_id_t *meta_attr_list = new cali_id_t[num_meta_elems];
cali_variant_t *meta_val_list = new cali_variant_t[num_meta_elems];
for (size_t i = 0; i < num_meta_elems; i++) {
meta_attr_list[i] = meta_attrs[i].m_attr_id;
meta_val_list[i] = meta_vals[i].c_variant;
}
m_attr_id = cali_create_attribute_with_metadata(
name, type, static_cast<int>(properties), num_meta_elems, meta_attr_list,
meta_val_list);
if (m_attr_id == CALI_INV_ID) {
throw std::runtime_error("Could not create attribute with metadata");
}
delete[] meta_val_list;
delete[] meta_attr_list;
}

PythonAttribute::PythonAttribute(cali_id_t id) {
if (id == CALI_INV_ID) {
throw std::runtime_error("Invalid attribute");
Expand Down Expand Up @@ -66,12 +92,16 @@ void create_caliper_instrumentation_mod(
// PythonAttribute bindings
py::class_<PythonAttribute> cali_attribute_type(caliper_instrumentation_mod,
"Attribute");
cali_attribute_type.def(
py::init<const char *, cali_attr_type>(), "",
py::arg(), py::arg());
cali_attribute_type.def(py::init<const char *, cali_attr_type>(), "",
py::arg(), py::arg());
cali_attribute_type.def(
py::init<const char *, cali_attr_type, cali_attr_properties>(), "",
py::arg(), py::arg(), py::arg("opt"));
cali_attribute_type.def(
py::init<const char *, cali_attr_type, cali_attr_properties,
std::vector<PythonAttribute &> &,
std::vector<PythonVariant &> &>(),
"");
cali_attribute_type.def_static("find_attribute",
&PythonAttribute::find_attribute);
cali_attribute_type.def_property_readonly("name", &PythonAttribute::name);
Expand Down
7 changes: 7 additions & 0 deletions bindings/python/instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "common.h"

#include "variant.h"

namespace cali {

class PythonAttribute {
Expand All @@ -12,6 +14,11 @@ class PythonAttribute {
PythonAttribute(const char *name, cali_attr_type type,
cali_attr_properties opt);

PythonAttribute(const char *name, cali_attr_type type,
cali_attr_properties opt,
std::vector<PythonAttribute &> &meta_attrs,
std::vector<PythonVariant &> &meta_vals);

static PythonAttribute find_attribute(const char *name);

const char *name() const;
Expand Down
9 changes: 7 additions & 2 deletions bindings/python/mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ bool pycaliper_is_initialized() { return cali_is_initialized() != 0; }
PYBIND11_MODULE(__pycaliper_impl, m) {
m.attr("__version__") = cali_caliper_version();

m.def("config_preset", [](std::map<const char *, const char *> &preset_map) {
for (auto kv : preset_map) {
cali_config_preset(kv.first, kv.second);
}
});
m.def("init", &cali_init);
m.def("is_initialized", &pycaliper_is_initialized);

auto types_mod = m.def_submodule("types");

py::enum_<cali_attr_type> c_attr_type(types_mod, "AttrTypeEnum");
py::enum_<cali_attr_type> c_attr_type(types_mod, "AttrType");
c_attr_type.value("CALI_TYPE_INV", CALI_TYPE_INV);
c_attr_type.value("CALI_TYPE_USR", CALI_TYPE_USR);
c_attr_type.value("CALI_TYPE_INT", CALI_TYPE_INT);
Expand All @@ -30,7 +35,7 @@ PYBIND11_MODULE(__pycaliper_impl, m) {
c_attr_type.export_values();

py::enum_<cali_attr_properties> c_attr_properties(types_mod,
"AttrPropertiesEnum");
"AttrProperties");
c_attr_properties.value("CALI_ATTR_DEFAULT", CALI_ATTR_DEFAULT);
c_attr_properties.value("CALI_ATTR_ASVALUE", CALI_ATTR_ASVALUE);
c_attr_properties.value("CALI_ATTR_NOMERGE", CALI_ATTR_NOMERGE);
Expand Down
1 change: 1 addition & 0 deletions bindings/python/pycaliper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pycaliper.__pycaliper_impl import (
__version__,
config_preset,
init,
is_initialized,
)
Expand Down
26 changes: 0 additions & 26 deletions bindings/python/pycaliper/types.py
Original file line number Diff line number Diff line change
@@ -1,27 +1 @@
from pycaliper.__pycaliper_impl.types import *

from enum import Enum


_CALI_TYPE_ENUM_PREFIX = "CALI_TYPE_"
_CALI_PROPERTIES_ENUM_PREFIX = "CALI_ATTR_"


AttrType = Enum(
"AttrType",
{
name[len(_CALI_TYPE_ENUM_PREFIX) :]: val
for name, val in AttrTypeEnum.__members__.items()
if name.startswith(_CALI_TYPE_ENUM_PREFIX)
},
)


AttrProperties = Enum(
"AttrProperties",
{
name[len(_CALI_PROPERTIES_ENUM_PREFIX) :]: val
for name, val in AttrPropertiesEnum.__members__.items()
if name.startswith(_CALI_PROPERTIES_ENUM_PREFIX)
},
)
25 changes: 25 additions & 0 deletions test/ci_app_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ set(CALIPER_CI_MPI_TEST_APPS
ci_test_mpi_channel_manager)
set(CALIPER_CI_Fortran_TEST_APPS
ci_test_f_ann)
set(CALIPER_CI_Python_TEST_APPS
ci_test_py_ann.py
)

foreach(app ${CALIPER_CI_CXX_TEST_APPS})
add_executable(${app} ${app}.cpp)
Expand Down Expand Up @@ -130,6 +133,28 @@ if (WITH_FORTRAN)
list(APPEND PYTHON_SCRIPTS test_fortran_api.py)
endif()

if (WITH_PYTHON_BINDINGS)
foreach(file ${CALIPER_CI_Python_TEST_APPS})
add_custom_target(${file} ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}/${file}
${CMAKE_CURRENT_BINARY_DIR}/${file})
endforeach()

list(APPEND PYTHON_SCRIPTS test_python_api.py)
endif()

if (WITH_PYTHON_BINDINGS)
foreach(file ${CALIPER_CI_Python_TEST_APPS})
add_custom_target(${file} ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}/${file}
${CMAKE_CURRENT_BINARY_DIR}/${file})
endforeach()

list(APPEND PYTHON_SCRIPTS test_python_api.py)
endif()

set(DATA_FILES
example_node_info.json)

Expand Down
74 changes: 74 additions & 0 deletions test/ci_app_tests/ci_test_py_ann.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# --- Caliper continuous integration test app for Python annotation interface

from pycaliper import config_preset
from pycaliper.instrumentation import (
Attribute,
set_global_byname,
begin_byname,
set_byname,
end_byname,
)
from pycaliper.types import AttrProperties
from pycaliper.variant import Variant
from pycaliper.config_manager import ConfigManager

import sys


def main():
config_preset({"CALI_CHANNEL_FLUSH_ON_EXIT", "false"})

mgr = ConfigManager()
if len(sys.argv) > 1:
mgr.add(sys.argv[1])

if mgr.error():
print("Caliper config error:", mgr.err_msg(), file=sys.stderr)
exit(-1)

mgr.start()

set_global_byname("global.double", 42.42)
set_global_byname("global.int", 1337)
set_global_byname("global.string", "my global string")
set_global_byname("global.uint", 42)

iter_attr = Attribute("iteration", AttrProperties.CALI_ATTR_ASVALUE)

begin_byname("phase", "loop")

for i in range(4):
iter_attr.begin(i)
iter_attr.end()

end_byname("phase")

begin_byname("ci_test_c_ann.meta-attr")

meta_attr = Attribute("meta-attr")
meta_val = Variant(47)

test_attr = Attribute(
"test-attr-with-metadata",
AttrProperties.CALI_ATTR_UNLIGNED,
[meta_attr],
[meta_val],
)

test_attr.set("abracadabra")

end_byname("ci_test_c_ann.meta-attr")

begin_byname("ci_test_c_ann.setbyname")

set_byname("attr.int", 20)
set_byname("attr.dbl", 1.25)
set_byname("attr.str", "fidibus")

end_byname("ci_test_c_ann.setbyname")

mgr.flush()


if __name__ == "__main__":
main()
137 changes: 137 additions & 0 deletions test/ci_app_tests/test_python_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Tests of the Python API

import sys

import unittest

import calipertest as cat


class CaliperPythonAPITest(unittest.TestCase):
"""Caliper Python API test cases"""

def test_py_ann_trace(self):
target_cmd = [
sys.executable,
"./ci_test_py_ann.py",
"event-trace,output=stdout",
]
query_cmd = ["../../src/tools/cali-query/cali-query", "-e"]

caliper_config = {"CALI_LOG_VERBOSITY": "0"}

query_output = cat.run_test_with_query(target_cmd, query_cmd, caliper_config)
snapshots = cat.get_snapshots_from_text(query_output)

self.assertTrue(len(snapshots) >= 10)

self.assertTrue(
cat.has_snapshot_with_keys(
snapshots, {"iteration", "phase", "time.duration.ns", "global.int"}
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots, {"event.end#phase": "loop", "phase": "loop"}
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots,
{"event.end#iteration": "3", "iteration": "3", "phase": "loop"},
)
)
self.assertTrue(
cat.has_snapshot_with_keys(
snapshots,
{"attr.int", "attr.dbl", "attr.str", "ci_test_c_ann.setbyname"},
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots, {"attr.int": "20", "attr.str": "fidibus"}
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots, {"test-attr-with-metadata": "abracadabra"}
)
)

def test_py_ann_globals(self):
target_cmd = [sys.executable, "./ci_test_py_ann.py"]
query_cmd = ["../../src/tools/cali-query/cali-query", "-e", "--list-globals"]

caliper_config = {
"CALI_CONFIG_PROFILE": "serial-trace",
"CALI_RECORDER_FILENAME": "stdout",
"CALI_LOG_VERBOSITY": "0",
}

query_output = cat.run_test_with_query(target_cmd, query_cmd, caliper_config)
snapshots = cat.get_snapshots_from_text(query_output)

self.assertTrue(len(snapshots) == 1)

self.assertTrue(
cat.has_snapshot_with_keys(
snapshots,
{
"global.double",
"global.string",
"global.int",
"global.uint",
"cali.caliper.version",
},
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots,
{
"global.int": "1337",
"global.string": "my global string",
"global.uint": "42",
},
)
)

def test_py_ann_metadata(self):
target_cmd = [sys.executable, "./ci_test_py_ann.py"]
query_cmd = [
"../../src/tools/cali-query/cali-query",
"-e",
"--list-attributes",
"--print-attributes",
"cali.attribute.name,cali.attribute.type,meta-attr",
]

caliper_config = {
"CALI_CONFIG_PROFILE": "serial-trace",
"CALI_RECORDER_FILENAME": "stdout",
"CALI_LOG_VERBOSITY": "0",
}

query_output = cat.run_test_with_query(target_cmd, query_cmd, caliper_config)
snapshots = cat.get_snapshots_from_text(query_output)

self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots,
{"cali.attribute.name": "meta-attr", "cali.attribute.type": "int"},
)
)
self.assertTrue(
cat.has_snapshot_with_attributes(
snapshots,
{
"cali.attribute.name": "test-attr-with-metadata",
"cali.attribute.type": "string",
"meta-attr": "47",
},
)
)


if __name__ == "__main__":
unittest.main()

0 comments on commit e6b3ce2

Please sign in to comment.