[lldb][NFC] Rewrite CPP11EnumTypes test to make it faster

TestCPP11EnumTypes is one of the most expensive tests on my system and takes
around 35 seconds to run. A relatively large amount of that time is actually
doing CPU intensive work it seems (and not waiting on timeouts like other
slow tests).

The main issue is that this test repeatedly compiles the same source files
with different compiler defines. The test is also including standard library
headers, so it will also build all system modules with the gmodules debug
info variant. This leads to the problem that this test ends up compiling all
system Clang modules 8 times (one for each subtest with a unique define). As
the system modules are quite large, this causes that this test spends most
of its runtime just recompiling all system modules on macOS.

There is also the small issue that this test is starting and start-stopping
the test process a few hundred times.

This rewrites the test to instead just use a macro to instantiate all the
enum types in a single source and uses global variables to test the values
(which means there is no more need to continue/stop or even start a process).

I kept running all the debug info variants (event though it doesn't seem really
relevant) to keep this as NFC as possible.

This reduced the test runtime by around 1.5 seconds on my system (or in relative
numbers, the runtime of this test decreases by 95%).
This commit is contained in:
Raphael Isemann 2020-09-04 12:29:40 +02:00
parent 2c9dbcda4f
commit 101f37a1b3
2 changed files with 63 additions and 178 deletions

View File

@ -1,7 +1,5 @@
"""Look up enum type information and check for correct display."""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
@ -12,145 +10,45 @@ class CPP11EnumTypesTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_int8_t(self):
"""Test C++11 enumeration class types as int8_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DSIGNED_ENUM_CLASS_TYPE=int8_t"'})
self.image_lookup_for_enum_type(True)
def check_enum(self, suffix):
"""
:param suffix The suffix of the enum type name (enum_<suffix>) that
should be checked.
:param test_values A list of integet values that shouldn't be converted
to any valid enum case.
"""
enum_name = "enum_" + suffix
unsigned = suffix.startswith("u")
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_int16_t(self):
"""Test C++11 enumeration class types as int16_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DSIGNED_ENUM_CLASS_TYPE=int16_t"'})
self.image_lookup_for_enum_type(True)
self.expect("image lookup -t " + enum_name,
patterns=["enum( struct| class) " + enum_name + " {"],
substrs=["Case1",
"Case2",
"Case3"])
# Test each case in the enum.
self.expect_expr("var1_" + suffix, result_type=enum_name, result_value="Case1")
self.expect_expr("var2_" + suffix, result_type=enum_name, result_value="Case2")
self.expect_expr("var3_" + suffix, result_type=enum_name, result_value="Case3")
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_int32_t(self):
"""Test C++11 enumeration class types as int32_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DSIGNED_ENUM_CLASS_TYPE=int32_t"'})
self.image_lookup_for_enum_type(True)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_int64_t(self):
"""Test C++11 enumeration class types as int64_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DSIGNED_ENUM_CLASS_TYPE=int64_t"'})
self.image_lookup_for_enum_type(True)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_uint8_t(self):
"""Test C++11 enumeration class types as uint8_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DUNSIGNED_ENUM_CLASS_TYPE=uint8_t"'})
self.image_lookup_for_enum_type(False)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_uint16_t(self):
"""Test C++11 enumeration class types as uint16_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DUNSIGNED_ENUM_CLASS_TYPE=uint16_t"'})
self.image_lookup_for_enum_type(False)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_uint32_t(self):
"""Test C++11 enumeration class types as uint32_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DUNSIGNED_ENUM_CLASS_TYPE=uint32_t"'})
self.image_lookup_for_enum_type(False)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test_uint64_t(self):
"""Test C++11 enumeration class types as uint64_t types."""
self.build(
dictionary={
'CFLAGS_EXTRAS': '"-DUNSIGNED_ENUM_CLASS_TYPE=uint64_t"'})
self.image_lookup_for_enum_type(False)
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break inside main().
self.line = line_number('main.cpp', '// Set break point at this line.')
def image_lookup_for_enum_type(self, is_signed):
"""Test C++11 enumeration class types."""
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
# Break inside the main.
bkpt_id = lldbutil.run_break_set_by_file_and_line(
self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped',
'stop reason = breakpoint'])
# The breakpoint should have a hit count of 1.
self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
substrs=[' resolved, hit count = 1'])
# Look up information about the 'DayType' enum type.
# Check for correct display.
self.expect("image lookup -t DayType", DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=['enum( struct| class) DayType {'],
substrs=['Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
'kNumDays',
'}'])
if is_signed:
enum_values = ['-4',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
'kNumDays',
'5']
if unsigned:
self.expect_expr("var_below_" + suffix, result_type=enum_name, result_value="199")
self.expect_expr("var_above_" + suffix, result_type=enum_name, result_value="203")
else:
enum_values = ['199',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
'kNumDays',
'208']
self.expect_expr("var_below_" + suffix, result_type=enum_name, result_value="-3")
self.expect_expr("var_above_" + suffix, result_type=enum_name, result_value="1")
bkpt = self.target().FindBreakpointByID(bkpt_id)
for enum_value in enum_values:
self.expect(
"frame variable day",
'check for valid enumeration value',
substrs=[enum_value])
lldbutil.continue_to_breakpoint(self.process(), bkpt)
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr36527')
@skipIf(dwarf_version=['<', '4'])
def test(self):
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.check_enum("uc")
self.check_enum("c")
self.check_enum("us")
self.check_enum("s")
self.check_enum("ui")
self.check_enum("i")
self.check_enum("ul")
self.check_enum("l")
self.check_enum("ull")
self.check_enum("ll")

View File

@ -1,41 +1,28 @@
#include <stdio.h>
#include <stdint.h>
#define DEFINE_UNSIGNED_ENUM(suffix, enum_type) \
enum class enum_##suffix : enum_type{Case1 = 200, Case2, Case3}; \
enum_##suffix var1_##suffix = enum_##suffix ::Case1; \
enum_##suffix var2_##suffix = enum_##suffix ::Case2; \
enum_##suffix var3_##suffix = enum_##suffix ::Case3; \
enum_##suffix var_below_##suffix = static_cast<enum_##suffix>(199); \
enum_##suffix var_above_##suffix = static_cast<enum_##suffix>(203);
#define DEFINE_SIGNED_ENUM(suffix, enum_type) \
enum class enum_##suffix : enum_type{Case1 = -2, Case2, Case3}; \
enum_##suffix var1_##suffix = enum_##suffix ::Case1; \
enum_##suffix var2_##suffix = enum_##suffix ::Case2; \
enum_##suffix var3_##suffix = enum_##suffix ::Case3; \
enum_##suffix var_below_##suffix = static_cast<enum_##suffix>(-3); \
enum_##suffix var_above_##suffix = static_cast<enum_##suffix>(1);
int main (int argc, char const *argv[])
{
#ifdef SIGNED_ENUM_CLASS_TYPE
typedef SIGNED_ENUM_CLASS_TYPE enum_integer_t;
enum class DayType : enum_integer_t {
Monday = -3,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
kNumDays
};
enum_integer_t day_value;
#else
typedef UNSIGNED_ENUM_CLASS_TYPE enum_integer_t;
enum class DayType : enum_integer_t {
Monday = 200,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
kNumDays
};
enum_integer_t day_value;
#endif
DEFINE_UNSIGNED_ENUM(uc, unsigned char)
DEFINE_SIGNED_ENUM(c, signed char)
DEFINE_UNSIGNED_ENUM(us, unsigned short int)
DEFINE_SIGNED_ENUM(s, signed short int)
DEFINE_UNSIGNED_ENUM(ui, unsigned int)
DEFINE_SIGNED_ENUM(i, signed int)
DEFINE_UNSIGNED_ENUM(ul, unsigned long)
DEFINE_SIGNED_ENUM(l, signed long)
DEFINE_UNSIGNED_ENUM(ull, unsigned long long)
DEFINE_SIGNED_ENUM(ll, signed long long)
for (day_value = (enum_integer_t)DayType::Monday - 1; day_value <= (enum_integer_t)DayType::kNumDays + 1; ++day_value)
{
DayType day = (DayType)day_value;
printf("day as int is %i\n", (int)day); // Set break point at this line.
}
return 0; // Break here for char tests
}
int main(int argc, char const *argv[]) { return 0; }