Added support for CUDA calls in sequence diagrams (#263)

This commit is contained in:
Bartek Kryza
2024-05-01 18:18:23 +02:00
parent dfb4f38ded
commit 67363013fe
25 changed files with 543 additions and 46 deletions

View File

@@ -9,13 +9,18 @@ file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml
set(TEST_CASES_REQUIRING_CXX20 t00056 t00058 t00059 t00065 t00069)
set(TEST_CASES_REQUIRING_CXX20_MODULES t00070 t00071 t00072
t30012 t30013 t30014 t30015)
set(TEST_CASES_REQUIRING_CUDA t20049 t20050)
if(ENABLE_CXX_MODULES_TEST_CASES)
message(STATUS "Enabling C++ modules test cases")
foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES})
list(APPEND TEST_CASES_REQUIRING_CXX20 ${CXX20_MOD_TC})
endforeach()
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
else()
message(STATUS "Disabling C++ modules test cases")
foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES})
list(FILTER TEST_CASE_SOURCES
EXCLUDE
@@ -23,10 +28,23 @@ else()
list(FILTER TEST_CASE_CONFIGS
EXCLUDE
REGEX ".*${CXX20_MOD_TC}.*")
endforeach()
endif(ENABLE_CXX_MODULES_TEST_CASES)
if(NOT ENABLE_CUDA_TEST_CASES)
message(STATUS "Enabling CUDA test cases")
foreach(CUDA_TC ${TEST_CASES_REQUIRING_CUDA})
list(FILTER TEST_CASE_SOURCES
EXCLUDE
REGEX ".*${CUDA_TC}.*")
list(FILTER TEST_CASE_CONFIGS
EXCLUDE
REGEX ".*${CUDA_TC}.*")
endforeach()
else()
message(STATUS "Enabling CUDA test cases")
endif(NOT ENABLE_CUDA_TEST_CASES)
set(CLANG_UML_TEST_LIBRARIES
clang-umllib
${YAML_CPP_LIBRARIES}
@@ -39,7 +57,6 @@ endif(MSVC)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 SUPPORTS_CXX_STD_20)
message(STATUS "Enabling C++20 test cases")
# Remove test cases which require C++20 if they are not supported here
if(SUPPORTS_CXX_STD_20 EQUAL -1
@@ -53,8 +70,10 @@ if(SUPPORTS_CXX_STD_20 EQUAL -1
EXCLUDE
REGEX ".*${CXX20_TC}.*")
endforeach()
message(STATUS "Disabling C++20 test cases")
else()
set(ENABLE_CXX_STD_20_TEST_CASES 1)
message(STATUS "Enabling C++20 test cases")
endif()
if(APPLE)

11
tests/t20049/.clang-uml Normal file
View File

@@ -0,0 +1,11 @@
diagrams:
t20049_sequence:
type: sequence
glob:
- t20049.cu
include:
namespaces:
- clanguml::t20049
using_namespace: clanguml::t20049
from:
- function: "clanguml::t20049::tmain()"

36
tests/t20049/t20049.cu Normal file
View File

@@ -0,0 +1,36 @@
#include "t20049.cuh"
namespace clanguml {
namespace t20049 {
constexpr unsigned long N{1000};
__device__ float square(float a) { return a * a; }
__global__ void vector_square_add(float *out, float *a, float *b, int n)
{
for (int i = 0; i < n; i++) {
out[i] = add(square(a[i]), square(b[i]));
}
}
int tmain()
{
float *a, *b, *out;
a = (float *)malloc(sizeof(float) * N);
b = (float *)malloc(sizeof(float) * N);
out = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++) {
a[i] = 1.0f;
b[i] = 2.0f;
}
vector_square_add<<<1, 1>>>(out, a, b, N);
return 0;
}
}
}

11
tests/t20049/t20049.cuh Normal file
View File

@@ -0,0 +1,11 @@
namespace clanguml {
namespace t20049 {
template <typename T> __device__ T add(T a, T b) { return a + b; }
__device__ float square(float a);
__global__ void vector_add(float *out, float *a, float *b, int n);
}
}

81
tests/t20049/test_case.h Normal file
View File

@@ -0,0 +1,81 @@
/**
* tests/t20049/test_case.h
*
* Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
TEST_CASE("t20049", "[test-case][sequence]")
{
auto [config, db] = load_config("t20049");
auto diagram = config.diagrams["t20049_sequence"];
REQUIRE(diagram->name == "t20049_sequence");
auto model = generate_sequence_diagram(*db, diagram);
REQUIRE(model->name() == "t20049_sequence");
{
auto src = generate_sequence_puml(diagram, *model);
AliasMatcher _A(src);
REQUIRE_THAT(src, StartsWith("@startuml"));
REQUIRE_THAT(src, EndsWith("@enduml\n"));
REQUIRE_THAT(src,
HasCall(_A("tmain()"),
_A("vector_square_add(float *,float *,float *,int)"), ""));
REQUIRE_THAT(src,
HasCall(_A("vector_square_add(float *,float *,float *,int)"),
_A("square(float)"), ""));
REQUIRE_THAT(src,
HasCall(_A("vector_square_add(float *,float *,float *,int)"),
_A("add<float>(float,float)"), ""));
save_puml(config.output_directory(), diagram->name + ".puml", src);
}
{
auto j = generate_sequence_json(diagram, *model);
using namespace json;
save_json(config.output_directory(), diagram->name + ".json", j);
}
{
auto src = generate_sequence_mermaid(diagram, *model);
mermaid::SequenceDiagramAliasMatcher _A(src);
using mermaid::HasCall;
REQUIRE_THAT(src,
HasCall(_A("tmain()"),
_A("<< CUDA Kernel >><br>vector_square_add(float *,float "
"*,float *,int)"),
""));
REQUIRE_THAT(src,
HasCall(_A("<< CUDA Kernel >><br>vector_square_add(float *,float "
"*,float *,int)"),
_A("<< CUDA Device >><br>square(float)"), ""));
REQUIRE_THAT(src,
HasCall(_A("<< CUDA Kernel >><br>vector_square_add(float *,float "
"*,float *,int)"),
_A("<< CUDA Device >><br>add<float>(float,float)"), ""));
save_mermaid(config.output_directory(), diagram->name + ".mmd", src);
}
}

12
tests/t20050/.clang-uml Normal file
View File

@@ -0,0 +1,12 @@
diagrams:
t20050_sequence:
type: sequence
glob:
- t20050.cu
include:
namespaces:
- clanguml::t20050
using_namespace: clanguml::t20050
combine_free_functions_into_file_participants: true
from:
- function: "clanguml::t20050::tmain()"

38
tests/t20050/t20050.cu Normal file
View File

@@ -0,0 +1,38 @@
#include "t20050.cuh"
namespace clanguml {
namespace t20050 {
constexpr unsigned long N{1000};
template <typename T> __device__ T add(T a, T b) { return a + b; }
__device__ float square(float a) { return a * a; }
__global__ void vector_square_add(float *out, float *a, float *b, int n)
{
for (int i = 0; i < n; i++) {
out[i] = add(square(a[i]), square(b[i]));
}
}
int tmain()
{
float *a, *b, *out;
a = (float *)malloc(sizeof(float) * N);
b = (float *)malloc(sizeof(float) * N);
out = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++) {
a[i] = 1.0f;
b[i] = 2.0f;
}
vector_square_add<<<1, 1>>>(out, a, b, N);
return 0;
}
}
}

9
tests/t20050/t20050.cuh Normal file
View File

@@ -0,0 +1,9 @@
namespace clanguml {
namespace t20050 {
__device__ float square(float a);
__global__ void vector_add(float *out, float *a, float *b, int n);
}
}

80
tests/t20050/test_case.h Normal file
View File

@@ -0,0 +1,80 @@
/**
* tests/t20050/test_case.h
*
* Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License 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.
*/
TEST_CASE("t20050", "[test-case][sequence]")
{
auto [config, db] = load_config("t20050");
auto diagram = config.diagrams["t20050_sequence"];
REQUIRE(diagram->name == "t20050_sequence");
auto model = generate_sequence_diagram(*db, diagram);
REQUIRE(model->name() == "t20050_sequence");
{
auto src = generate_sequence_puml(diagram, *model);
AliasMatcher _A(src);
REQUIRE_THAT(src, StartsWith("@startuml"));
REQUIRE_THAT(src, EndsWith("@enduml\n"));
// Check if all calls exist
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Kernel >>\\\\nvector_square_add(float *,float *,float "
"*,int)"));
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Device >>\\\\nsquare(float)"));
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Device >>\\\\nadd<float>(float,float)"));
save_puml(config.output_directory(), diagram->name + ".puml", src);
}
{
auto j = generate_sequence_json(diagram, *model);
using namespace json;
save_json(config.output_directory(), diagram->name + ".json", j);
}
{
auto src = generate_sequence_mermaid(diagram, *model);
mermaid::SequenceDiagramAliasMatcher _A(src);
using mermaid::HasCall;
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Kernel >><br>vector_square_add(float *,float *,float "
"*,int)"));
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Device >><br>square(float)"));
REQUIRE_THAT(src,
HasCall(_A("t20050.cu"), _A("t20050.cu"),
"<< CUDA Device >><br>add<float>(float,float)"));
save_mermaid(config.output_directory(), diagram->name + ".mmd", src);
}
}

View File

@@ -475,6 +475,8 @@ using namespace clanguml::test::matchers;
#include "t20046/test_case.h"
#include "t20047/test_case.h"
#include "t20048/test_case.h"
#include "t20049/test_case.h"
#include "t20050/test_case.h"
///
/// Package diagram tests

View File

@@ -169,17 +169,11 @@ public:
bool match(T const &in) const override
{
std::istringstream fin(in);
std::string line;
std::regex r{m_is_response ? response_pattern : call_pattern};
while (std::getline(fin, line)) {
std::smatch base_match;
std::regex_search(in, base_match, r);
if (base_match.size() > 0)
return true;
}
std::smatch base_match;
std::regex_search(in, base_match, r);
if (base_match.size() > 0)
return true;
return false;
}
@@ -255,17 +249,11 @@ public:
bool match(T const &in) const override
{
std::istringstream fin(in);
std::string line;
std::regex r{m_is_response ? response_pattern : call_pattern};
while (std::getline(fin, line)) {
std::smatch base_match;
std::regex_search(in, base_match, r);
if (base_match.size() > 0)
return true;
}
std::smatch base_match;
std::regex_search(in, base_match, r);
if (base_match.size() > 0)
return true;
return false;
}

View File

@@ -364,6 +364,15 @@ test_cases:
- name: t20047
title: Test case for 'call' comment directive
description:
- name: t20048
title: Test case for message comments
description:
- name: t20049
title: Test case for CUDA kernel calls
description:
- name: t20050
title: Test case for CUDA kernel calls with participants combined to file
description:
Package diagrams:
- name: t30001
title: Basic package diagram test case