Skip to content

Commit 6113b48

Browse files
committed
fable: Add example stress test with generated code
1 parent eba5c21 commit 6113b48

File tree

6 files changed

+232
-0
lines changed

6 files changed

+232
-0
lines changed

fable/examples/stress/CMakeLists.txt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
2+
3+
project(fable_stress_test LANGUAGES CXX)
4+
5+
set(LARGE_STRUCT_SIZE 1000 CACHE NUMBER "Number of members of Large struct")
6+
7+
find_package(CLI11 REQUIRED)
8+
find_package(fable REQUIRED)
9+
find_package(fmt REQUIRED)
10+
11+
# Executable ---------------------------------------------------------
12+
add_custom_command(
13+
OUTPUT large_struct.hxx
14+
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.py ${LARGE_STRUCT_SIZE} ${CMAKE_CURRENT_BINARY_DIR}/large_struct.hxx
15+
VERBATIM
16+
)
17+
add_executable(stress
18+
src/main.cpp
19+
large_struct.hxx
20+
)
21+
target_include_directories(stress
22+
PRIVATE
23+
${CMAKE_CURRENT_BINARY_DIR}
24+
)
25+
set_target_properties(stress PROPERTIES
26+
CXX_STANDARD 17
27+
CXX_STANDARD_REQUIRED ON
28+
)
29+
target_link_libraries(stress
30+
PRIVATE
31+
fable::fable
32+
fmt::fmt
33+
CLI11::CLI11
34+
)

fable/examples/stress/Makefile

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This is a minimal Makefile to show how this example project
2+
# can be built with Conan and CMake.
3+
4+
# All generated and compiled output is in this directory.
5+
BUILD_DIR := build
6+
7+
# The build type must be synchronized between Conan (host build type)
8+
# and CMake, otherwise you will get strange and unhelpful errors.
9+
BUILD_TYPE := Release
10+
CMAKE_BUILD_TYPE := $(shell echo ${BUILD_TYPE} | tr '[:upper:]' '[:lower:]')
11+
12+
# This is the output that Conan generates when using
13+
# `CMakeToolchain` generator AND the `cmake_layout` layout.
14+
TOOLCHAIN_FILE := ${BUILD_DIR}/${BUILD_TYPE}/generators/conan_toolchain.cmake
15+
16+
# How many variables should the "Large" struct have?
17+
LARGE_STRUCT_SIZE := 1000
18+
19+
.PHONY: all clean
20+
all: ${TOOLCHAIN_FILE}
21+
cmake --build --preset=${CMAKE_BUILD_TYPE}
22+
23+
${TOOLCHAIN_FILE}:
24+
conan install . --build=missing --install-folder=${BUILD_DIR} -s:h build_type=${BUILD_TYPE}
25+
cmake --preset=${CMAKE_BUILD_TYPE} -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DLARGE_STRUCT_SIZE=${LARGE_STRUCT_SIZE}
26+
27+
clean:
28+
-rm -r ${BUILD_DIR}
29+
-rm CMakeUserPresets.json

fable/examples/stress/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This example project stresses the compiler by forcing it to compile
2+
an extremely large struct.

fable/examples/stress/conanfile.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This is a minimal conanfile.txt to show how this example project
2+
# can be built with Conan and CMake.
3+
4+
[requires]
5+
cli11/2.3.2
6+
fable/[>=0.20.0, include_prerelease=True]@cloe/develop
7+
fmt/9.1.0
8+
boost/[>=1.65.1]
9+
10+
[generators]
11+
CMakeDeps
12+
CMakeToolchain
13+
14+
[layout]
15+
cmake_layout

fable/examples/stress/gen.py

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env python3
2+
3+
import random
4+
import string
5+
import argparse
6+
7+
SIMPLE_TYPES = [
8+
"bool",
9+
"uint8_t",
10+
"uint16_t",
11+
"uint32_t",
12+
"uint64_t",
13+
"int8_t",
14+
"int16_t",
15+
"int32_t",
16+
"int64_t",
17+
"std::string",
18+
]
19+
20+
COMPLEX_TYPES = [
21+
"std::vector",
22+
"std::map",
23+
"boost::optional",
24+
# "std::array", # not supported yet
25+
]
26+
27+
ALL_TYPES = SIMPLE_TYPES + COMPLEX_TYPES
28+
29+
def generate_random_type():
30+
def _tvector():
31+
inner = random.choice(SIMPLE_TYPES)
32+
return f"std::vector<{inner}>"
33+
34+
def _tmap():
35+
inner = random.choice(SIMPLE_TYPES)
36+
return f"std::map<std::string, {inner}>"
37+
38+
def _toptional():
39+
inner = random.choice(SIMPLE_TYPES)
40+
return f"boost::optional<{inner}>"
41+
42+
def _tarray():
43+
inner = random.choice(SIMPLE_TYPES)
44+
length = random.randint(2, 24)
45+
return f"std::array<{inner}, {length}>"
46+
47+
mapper = {
48+
"std::vector": _tvector,
49+
"std::map": _tmap,
50+
"boost::optional": _toptional,
51+
}
52+
53+
result = random.choice(ALL_TYPES)
54+
if result in COMPLEX_TYPES:
55+
return mapper[result]()
56+
return result
57+
58+
def generate_random_word():
59+
letters = string.ascii_letters
60+
return ''.join(random.choice(letters) for _ in range(20))
61+
62+
TEMPLATE = string.Template("""
63+
#pragma once
64+
65+
struct Large : public fable::Confable {
66+
$variable_lines
67+
68+
CONFABLE_SCHEMA(Large) {
69+
using namespace fable;
70+
return Schema{
71+
$schema_lines
72+
};
73+
}
74+
};
75+
""")
76+
77+
def generate(count) -> str:
78+
variable_lines = []
79+
schema_lines = []
80+
for i in range(count):
81+
random_word = generate_random_word()
82+
variable_lines.append(f"{generate_random_type()} v{i};")
83+
schema_lines.append('{{"{0}", make_schema(&v{1}, "")}},'.format(random_word, i))
84+
result = TEMPLATE.substitute({
85+
"variable_lines": "\n ".join(variable_lines),
86+
"schema_lines": "\n ".join(schema_lines),
87+
})
88+
return result
89+
90+
def main():
91+
parser = argparse.ArgumentParser()
92+
parser.add_argument("count", default=10, type=int)
93+
parser.add_argument("output", default="-", type=str)
94+
args = parser.parse_args()
95+
96+
result = generate(args.count)
97+
if args.output == "-":
98+
print(result)
99+
else:
100+
with open(args.output, "w") as file:
101+
file.write(result)
102+
103+
if __name__ == "__main__":
104+
main()

fable/examples/stress/src/main.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2021 Robert Bosch GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
19+
/**
20+
* \file fable/examples/stress/src/main.cpp
21+
*
22+
* In this example application, we will stress-test the compilation.
23+
* We will be re-using types from the contacts example.
24+
*/
25+
26+
#include <iostream> // for std::{cout, cerr}
27+
#include <string> // for std::string<>
28+
#include <vector> // for std::vector<>
29+
30+
#include <fmt/format.h> // for fmt::format
31+
#include <CLI/CLI.hpp> // for CLI::App
32+
#include <boost/optional.hpp> // for boost::optional<>
33+
34+
#include <fable/confable.hpp> // for fable::{Confable, CONFABLE_SCHEMA}
35+
#include <fable/schema.hpp> // for fable::{Schema, String}
36+
#include <fable/utility.hpp> // for fable::{read_conf}
37+
38+
#include "large_struct.hxx"
39+
40+
int main(int argc, char** argv) {
41+
// Parse command line arguments:
42+
CLI::App app("Fable Stress Test Example");
43+
std::string filename;
44+
CLI11_PARSE(app, argc, argv);
45+
46+
Large large;
47+
std::cout << large.schema().to_json().dump(2) << std::endl;
48+
}

0 commit comments

Comments
 (0)