@@ -130,9 +130,6 @@ private function splitTestsByGroup(Generator $tests): array
130
130
131
131
private function splitTestsByRuntime (Generator $ tests , TimeReport $ timeReport ): array
132
132
{
133
- $ totalRuntime = $ timeReport ->totalRuntime ();
134
- $ avgRuntime = $ totalRuntime / $ this ->groupCount ;
135
-
136
133
$ skippedTests = [];
137
134
$ testsWithRuntime = [];
138
135
$ testsWithoutRuntime = [];
@@ -151,31 +148,41 @@ private function splitTestsByRuntime(Generator $tests, TimeReport $timeReport):
151
148
}
152
149
}
153
150
151
+ // Reverse sort, the larger runtimes are hard to fit than the smaller
152
+ // ones, so lets get them out of the way first.
154
153
arsort ($ testsWithRuntime );
155
154
156
155
$ sums = array_fill (0 , $ this ->groupCount , 0 );
157
156
$ groups = array_fill (0 , $ this ->groupCount , []);
158
157
159
- $ addedOne = false ;
158
+ $ maxLoops = 3 * $ this -> groupCount ;
160
159
foreach ($ testsWithRuntime as $ testPath => $ runtime ) {
161
- $ added = false ;
162
- $ idx = null ;
163
- foreach ($ sums as $ idx => $ sum ) {
164
- if (($ sum + $ runtime ) < $ avgRuntime || !$ addedOne ) {
160
+ $ idx = 0 ;
161
+ $ loops = 0 ;
162
+ while (true ) {
163
+ if ($ loops > $ maxLoops ) {
164
+ throw new TaskException (
165
+ $ this ,
166
+ "Max loop count ( {$ maxLoops }) reached. "
167
+ );
168
+ }
169
+
170
+ $ sum = $ sums [$ idx ];
171
+ $ prevIdx = $ idx - 1 ;
172
+ if ($ prevIdx < 0 ) {
173
+ $ prevIdx = $ this ->groupCount - 1 ;
174
+ }
175
+ $ nextIdx = $ idx + 1 ;
176
+ if ($ nextIdx === $ this ->groupCount ) {
177
+ $ nextIdx = 0 ;
178
+ }
179
+ if ($ sum === 0 || ($ sum < $ sums [$ prevIdx ] && $ sum < $ sums [$ nextIdx ])) {
180
+ $ sums [$ idx ] += $ runtime ;
165
181
$ groups [$ idx ][] = $ testPath ;
166
- $ sum += $ runtime ;
167
- $ sums [$ idx ] = $ sum ;
168
- $ addedOne = true ;
169
- $ added = true ;
170
182
break ;
171
183
}
172
- }
173
- if (!$ added ) {
174
- if ($ idx === null ) {
175
- $ idx = $ this ->groupCount - 1 ;
176
- }
177
- $ groups [$ idx ][] = $ testPath ;
178
- $ sums [$ idx ] += $ runtime ;
184
+ $ idx ++;
185
+ $ loops ++;
179
186
}
180
187
}
181
188
@@ -190,6 +197,8 @@ private function splitTestsByRuntime(Generator $tests, TimeReport $timeReport):
190
197
}
191
198
}
192
199
200
+ // Add skipped tests onto the last group as they take relatively no time
201
+ // to run.
193
202
$ maxGroupIdx = $ this ->groupCount - 1 ;
194
203
if (count ($ skippedTests ) > 0 ) {
195
204
$ groups [$ maxGroupIdx ] = array_merge ($ groups [$ maxGroupIdx ], $ skippedTests );
0 commit comments