Coverage for mlos_bench/mlos_bench/tests/tunables/tunable_slice_references_test.py: 97%

58 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-06 00:35 +0000

1# 

2# Copyright (c) Microsoft Corporation. 

3# Licensed under the MIT License. 

4# 

5""" 

6Unit tests for unique references to tunables when they're loaded multiple times. 

7""" 

8 

9import json5 as json 

10import pytest 

11 

12from mlos_bench.tunables.tunable_groups import TunableGroups 

13 

14 

15def test_duplicate_merging_tunable_groups(tunable_groups_config: dict) -> None: 

16 """ 

17 Check that the merging logic of tunable groups works as expected. 

18 """ 

19 parent_tunables = TunableGroups(tunable_groups_config) 

20 

21 # Pretend we loaded this one from disk another time. 

22 tunables_dup = TunableGroups(tunable_groups_config) 

23 

24 (tunable, covariant_group) = next(iter(parent_tunables)) 

25 (tunable_dup, covariant_group_dup) = next(iter(tunables_dup)) 

26 

27 assert tunable == tunable_dup 

28 assert covariant_group == covariant_group_dup 

29 

30 # Test merging prior to making any changes. 

31 parent_tunable_copy = parent_tunables.copy() 

32 parent_tunables = parent_tunables.merge(tunables_dup) 

33 

34 # Check that they're the same. 

35 assert covariant_group == covariant_group_dup 

36 assert parent_tunables == tunables_dup 

37 assert parent_tunables == parent_tunable_copy 

38 

39 (tunable_retry, covariant_group_retry) = next(iter(parent_tunables)) 

40 assert tunable == tunable_retry 

41 assert covariant_group == covariant_group_retry 

42 

43 # Update a value to indicate that they're separate copies. 

44 if tunable.is_categorical: 

45 tunable.category = [x for x in tunable.categories if x != tunable.category][0] 

46 elif tunable.is_numerical: 

47 tunable.numerical_value += 1 

48 

49 # Check that they're separate. 

50 assert tunable != tunable_dup 

51 assert covariant_group != covariant_group_dup 

52 assert parent_tunables != tunables_dup 

53 

54 # Should be ok since we only changed the value. 

55 parent_tunable_copy = parent_tunables.copy() 

56 parent_tunables = parent_tunables.merge(tunables_dup) 

57 

58 # Make sure nothing changed in the parent. 

59 assert tunable != tunable_dup 

60 assert covariant_group != covariant_group_dup 

61 assert parent_tunables != tunables_dup 

62 assert parent_tunables == parent_tunable_copy 

63 

64 

65def test_overlapping_group_merge_tunable_groups(tunable_groups_config: dict) -> None: 

66 """ 

67 Check that the merging logic of tunable groups works as expected. 

68 """ 

69 parent_tunables = TunableGroups(tunable_groups_config) 

70 

71 # This config should overlap with the parent config. 

72 # (same group name, different param name, different values) 

73 other_tunables_json = """ 

74 { 

75 "boot": { 

76 "cost": 300, 

77 "params": { 

78 "noidle": { 

79 "description": "(different) idling method", 

80 "type": "categorical", 

81 "default": "nomwait", 

82 "values": ["nohalt", "nomwait", "idle"] 

83 } 

84 } 

85 } 

86 } 

87 """ 

88 

89 other_tunables_config = json.loads(other_tunables_json) 

90 other_tunables = TunableGroups(other_tunables_config) 

91 

92 with pytest.raises(ValueError): 

93 parent_tunables.merge(other_tunables) 

94 

95 

96def test_bad_extended_merge_tunable_group(tunable_groups_config: dict) -> None: 

97 """ 

98 Check that the merging logic of tunable groups works as expected. 

99 """ 

100 parent_tunables = TunableGroups(tunable_groups_config) 

101 

102 # This config should overlap with the parent config. 

103 # (different group name, same param name) 

104 other_tunables_json = """ 

105 { 

106 "new-group": { 

107 "cost": 300, 

108 "params": { 

109 "idle": { 

110 "type": "categorical", 

111 "description": "Idling method", 

112 "default": "mwait", 

113 "values": ["halt", "mwait", "noidle"] 

114 } 

115 } 

116 } 

117 } 

118 """ 

119 

120 other_tunables_config = json.loads(other_tunables_json) 

121 other_tunables = TunableGroups(other_tunables_config) 

122 

123 with pytest.raises(ValueError): 

124 parent_tunables.merge(other_tunables) 

125 

126 

127def test_good_extended_merge_tunable_group(tunable_groups_config: dict) -> None: 

128 """ 

129 Check that the merging logic of tunable groups works as expected. 

130 """ 

131 parent_tunables = TunableGroups(tunable_groups_config) 

132 

133 # This config should overlap with the parent config. 

134 # (different group name, same param name) 

135 other_tunables_json = """ 

136 { 

137 "new-group": { 

138 "cost": 300, 

139 "params": { 

140 "new-param": { 

141 "type": "int", 

142 "default": 0, 

143 "range": [0, 10] 

144 } 

145 } 

146 } 

147 } 

148 """ 

149 

150 other_tunables_config = json.loads(other_tunables_json) 

151 other_tunables = TunableGroups(other_tunables_config) 

152 

153 assert "new-param" not in parent_tunables 

154 assert "new-param" in other_tunables 

155 

156 parent_tunables = parent_tunables.merge(other_tunables) 

157 

158 assert "new-param" in parent_tunables 

159 (tunable_param, covariant_group) = parent_tunables.get_tunable("new-param") 

160 assert tunable_param.name == "new-param" 

161 assert covariant_group.name == "new-group"