def disabled_test_estimates_with_small_builder_pool(self): # Test that a reduced builder pool results in longer dispatch time # estimates. vim_build, vim_job = find_job(self, 'vim', '386') disable_builders(self, '386', True) # Re-enable one builder. builder = self.builders[(self.x86_proc.id, True)][0] builder.builderok = True # Dispatch the firefox job to it. assign_to_builder(self, 'firefox', 1, '386') # Dispatch the head job, making postgres/386 the new head job and # resulting in a 240 seconds head job dispatch delay. assign_to_builder(self, 'xxr-daptup', 1, None) check_mintime_to_builder(self, vim_job, 240) # Re-enable another builder. builder = self.builders[(self.x86_proc.id, True)][1] builder.builderok = True # Assign a job to it. assign_to_builder(self, 'gedit', 2, '386') check_mintime_to_builder(self, vim_job, 120) xxr_build, xxr_job = find_job(self, 'xxr-apt', None) # The delay of 2627+120 seconds is calculated as follows: # 386 jobs : (6+10+12+14+16)*60/2 = 1740 # processor-independent jobs : # (12:56 + 11:05 + 18:30 + 16:38 + 14:47)/5 = 887 # waiting time for next builder: = 120 self.assertEqual(2, builders_for_job(vim_job)) self.assertEqual(9, builders_for_job(xxr_job)) check_estimate(self, vim_job, 2747)
def test_proc_indep_virtual_true(self): xxr_build, xxr_job = find_job(self, 'xxr-apt-build', None) # The delay of 1802 seconds is calculated as follows: # 386 jobs: 16*60 = 960 # processor-independent jobs: # (11:05 + 18:30 + 16:38 + 14:47 + 9:14)/5 = 842 check_estimate(self, xxr_job, 1802)
def test_estimation_binary_virtual_same_score(self): vim_build, vim_job = find_job(self, 'vim', '386') # The apg job is ahead of the vim job. # The delay of 1527 seconds is calculated as follows: # 386 jobs: (6+10+12+14+16)*60/5 = 696 # processor-independent jobs: # (12:56 + 11:05 + 18:30 + 16:38 + 14:47 + 9:14)/6 = 831 check_estimate(self, vim_job, 1527)
def test_estimation_binary_virtual(self): gcc_build, gcc_job = find_job(self, 'gcc', '386') # The delay of 1671 seconds is calculated as follows: # 386 jobs: (12+14+16)*60/3 = 840 # processor-independent jobs: # (12:56 + 11:05 + 18:30 + 16:38 + 14:47 + 9:14)/6 = 831 check_estimate(self, gcc_job, 1671) self.assertEqual(5, builders_for_job(gcc_job))
def test_estimation_binary_virtual_long_queue(self): gedit_build, gedit_job = find_job(self, 'gedit', '386') # The delay of 1671 seconds is calculated as follows: # 386 jobs: # (4+6+8+10+12+14+16)*60/5 = 840 # processor-independent jobs: # (12:56 + 11:05 + 18:30 + 16:38 + 14:47 + 9:14)/6 = 831 check_estimate(self, gedit_job, 1671)
def test_estimation_binary_virtual_headjob(self): # The head job only waits for the next builder to become available. disable_builders(self, '386', True) # Re-enable one builder. builder = self.builders[(self.x86_proc.id, True)][0] builder.builderok = True # Assign a job to it. assign_to_builder(self, 'gedit', 1, '386') # Dispatch the head job, making postgres/386 the new head job. assign_to_builder(self, 'xxr-daptup', 2, None) postgres_build, postgres_job = find_job(self, 'postgres', '386') check_estimate(self, postgres_job, 120)
def disabled_test_job_delay_for_binary_builds(self): # One of four builders for the 'flex' build is immediately available. flex_build, flex_job = find_job(self, 'flex', 'hppa') check_mintime_to_builder(self, flex_job, 0) # The delay will be 900 (= 15*60) + 222 seconds check_delay_for_job(self, flex_job, 1122) # Assign the postgres job to a builder. assign_to_builder(self, 'postgres', 1, 'hppa') # The 'postgres' job is not pending any more. Now only the 222 # seconds (the estimated duration of the platform-independent job) # should be returned. check_delay_for_job(self, flex_job, 222) # How about some estimates for x86 builds? _bison_build, bison_job = find_job(self, 'bison', '386') check_mintime_to_builder(self, bison_job, 0) # The delay will be 900 (= (14+16)*60/2) + 222 seconds. check_delay_for_job(self, bison_job, 1122) # The 2 tests that follow exercise the estimation in conjunction with # longer pending job queues. Please note that the sum of estimates for # the '386' jobs is divided by 4 which is the number of native '386' # builders. # Also, this tests that jobs with equal score but a lower 'job' value # (i.e. older jobs) are queued ahead of the job of interest (JOI). _vim_build, vim_job = find_job(self, 'vim', '386') check_mintime_to_builder(self, vim_job, 0) # The delay will be 870 (= (6+10+12+14+16)*60/4) + 122 (= (222+22)/2) # seconds. check_delay_for_job(self, vim_job, 992) _gedit_build, gedit_job = find_job(self, 'gedit', '386') check_mintime_to_builder(self, gedit_job, 0) # The delay will be # 1080 (= (4+6+8+10+12+14+16)*60/4) + 122 (= (222+22)/2) # seconds. check_delay_for_job(self, gedit_job, 1172)
def disabled_test_job_delay_for_recipe_builds(self): # One of the 9 builders for the 'bash' build is immediately available. bash_build, bash_job = find_job(self, 'xx-recipe-bash', None) check_mintime_to_builder(self, bash_job, 0) # The delay will be 960 + 780 + 222 = 1962, where # hppa job delays: 960 = (9+11+13+15)*60/3 # 386 job delays: 780 = (10+12+14+16)*60/4 check_delay_for_job(self, bash_job, 1962) # One of the 9 builders for the 'zsh' build is immediately available. zsh_build, zsh_job = find_job(self, 'xx-recipe-zsh', None) check_mintime_to_builder(self, zsh_job, 0) # The delay will be 0 since this is the head job. check_delay_for_job(self, zsh_job, 0) # Assign the zsh job to a builder. self.assertEqual((None, False), bash_job._getHeadJobPlatform()) assign_to_builder(self, 'xx-recipe-zsh', 1, None) self.assertEqual((1, False), bash_job._getHeadJobPlatform()) # Now that the highest-scored job is out of the way, the estimation # for the 'bash' recipe build is 222 seconds shorter. # The delay will be 960 + 780 = 1740, where # hppa job delays: 960 = (9+11+13+15)*60/3 # 386 job delays: 780 = (10+12+14+16)*60/4 check_delay_for_job(self, bash_job, 1740) _postgres_build, postgres_job = find_job(self, 'postgres', '386') # The delay will be 0 since this is the head job now. check_delay_for_job(self, postgres_job, 0) # Also, the platform of the postgres job is returned since it *is* # the head job now. pg_platform = (postgres_job.processor.id, postgres_job.virtualized) self.assertEqual(pg_platform, postgres_job._getHeadJobPlatform())
def test_free_builder_counts(self): # Make sure the builder numbers are correct. The builder data will # be the same for all of our builds. build = self.builds[0] # The build in question is an x86/native one. self.assertEqual(self.x86_proc.id, build.processor.id) self.assertEqual(False, build.virtualized) # To test this non-interface method, we need to remove the # security proxy. bq = removeSecurityProxy(build.buildqueue_record) builder_stats = get_builder_data() # We have 4 x86 native builders. self.assertEqual( 4, builder_stats[(self.x86_proc.id, False)], "The number of native x86 builders is wrong") # Initially all 4 builders are free. free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(4, free_count) # Once we assign a build to one of them we should see the free # builders count drop by one. assign_to_builder(self, 'postgres', 1) free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(3, free_count) # When we assign another build to one of them we should see the free # builders count drop by one again. assign_to_builder(self, 'gcc', 2) free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(2, free_count) # Let's use up another builder. assign_to_builder(self, 'apg', 3) free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(1, free_count) # And now for the last one. assign_to_builder(self, 'flex', 4) free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(0, free_count) # If we reset the 'flex' build the builder that was assigned to it # will be free again. build, bq = find_job(self, 'flex') bq.reset() free_count = get_free_builders_count( build.processor, build.virtualized) self.assertEqual(1, free_count)
def setUp(self): """Add 2 'build source package from recipe' builds to the mix. The two platform-independent jobs will have a score of 1025 and 1053 respectively. In case of jobs with equal scores the one with the lesser 'job' value (i.e. the older one wins). 3, gedit, p: hppa, v:False e:0:01:00 *** s: 1003 4, gedit, p: 386, v:False e:0:02:00 *** s: 1006 5, firefox, p: hppa, v:False e:0:03:00 *** s: 1009 6, firefox, p: 386, v:False e:0:04:00 *** s: 1012 7, apg, p: hppa, v:False e:0:05:00 *** s: 1015 9, vim, p: hppa, v:False e:0:07:00 *** s: 1021 10, vim, p: 386, v:False e:0:08:00 *** s: 1024 8, apg, p: 386, v:False e:0:06:00 *** s: 1024 --> 19, xx-recipe-bash, p: None, v:False e:0:00:22 *** s: 1025 11, gcc, p: hppa, v:False e:0:09:00 *** s: 1027 12, gcc, p: 386, v:False e:0:10:00 *** s: 1030 13, bison, p: hppa, v:False e:0:11:00 *** s: 1033 14, bison, p: 386, v:False e:0:12:00 *** s: 1036 15, flex, p: hppa, v:False e:0:13:00 *** s: 1039 16, flex, p: 386, v:False e:0:14:00 *** s: 1042 17, postgres, p: hppa, v:False e:0:15:00 *** s: 1045 18, postgres, p: 386, v:False e:0:16:00 *** s: 1048 --> 20, xx-recipe-zsh, p: None, v:False e:0:03:42 *** s: 1053 p=processor, v=virtualized, e=estimated_duration, s=score """ super(TestMultiArchJobDelayEstimation, self).setUp() job = self.makeCustomBuildQueue( virtualized=False, estimated_duration=22, sourcename=u'xx-recipe-bash', score=1025) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( virtualized=False, estimated_duration=222, sourcename=u'xx-recipe-zsh', score=1053) self.builds.append(job.specific_build) # Assign the same score to the '386' vim and apg build jobs. _apg_build, apg_job = find_job(self, 'apg', '386') apg_job.lastscore = 1024
def test_proc_indep_virtual_false_headjob(self): xxr_build, xxr_job = find_job(self, 'xxr-auto-apt', None) # This job is at the head of the queue for native builders and # will get dispatched within the next 5 seconds. check_estimate(self, xxr_job, 5)
def test_proc_indep_virtual_false(self): xxr_build, xxr_job = find_job(self, 'xxr-aptitude', None) # The delay of 1403 seconds is calculated as follows: # hppa jobs: (9+11+13+15)*60/3 = 960 # processor-independent jobs: 7:23 = 443 check_estimate(self, xxr_job, 1403)
def test_proc_indep_virtual_null_headjob(self): xxr_build, xxr_job = find_job(self, 'xxr-daptup', None) # This job is at the head of the queue for virtualized builders and # will get dispatched within the next 5 seconds. check_estimate(self, xxr_job, 5)
def assign_to_builder(test, job_name, builder_number, processor='386'): """Simulate assigning a build to a builder.""" build, bq = find_job(test, job_name, processor) builder = nth_builder(test, bq, builder_number) bq.markAsBuilding(builder)
def test_min_time_to_next_builder(self): """When is the next builder capable of running the job at the head of the queue becoming available?""" # Test the estimation of the minimum time until a builder becomes # available. # The builds will be set up as follows: # # gedit, p: 386, v:False e:0:01:00 *** s: 1001 # firefox, p: 386, v:False e:0:02:00 *** s: 1002 # apg, p: 386, v:False e:0:03:00 *** s: 1003 # vim, p: 386, v:False e:0:04:00 *** s: 1004 # gcc, p: 386, v:False e:0:05:00 *** s: 1005 # bison, p: 386, v:False e:0:06:00 *** s: 1006 # flex, p: 386, v:False e:0:07:00 *** s: 1007 # postgres, p: 386, v:False e:0:08:00 *** s: 1008 # # p=processor, v=virtualized, e=estimated_duration, s=score # This will be the job of interest. apg_build, apg_job = find_job(self, 'apg') # One of four builders for the 'apg' build is immediately available. check_mintime_to_builder(self, apg_job, 0) # Assign the postgres job to a builder. assign_to_builder(self, 'postgres', 1) # Now one builder is gone. But there should still be a builder # immediately available. check_mintime_to_builder(self, apg_job, 0) assign_to_builder(self, 'flex', 2) check_mintime_to_builder(self, apg_job, 0) assign_to_builder(self, 'bison', 3) check_mintime_to_builder(self, apg_job, 0) assign_to_builder(self, 'gcc', 4) # Now that no builder is immediately available, the shortest # remaing build time (based on the estimated duration) is returned: # 300 seconds # This is equivalent to the 'gcc' job's estimated duration. check_mintime_to_builder(self, apg_job, 300) # Now we pretend that the 'postgres' started 6 minutes ago. Its # remaining execution time should be 2 minutes = 120 seconds and # it now becomes the job whose builder becomes available next. build, bq = find_job(self, 'postgres') set_remaining_time_for_running_job(bq, 120) check_mintime_to_builder(self, apg_job, 120) # What happens when jobs overdraw the estimated duration? Let's # pretend the 'flex' job started 8 minutes ago. build, bq = find_job(self, 'flex') set_remaining_time_for_running_job(bq, -60) # In such a case we assume that the job will complete within 2 # minutes, this is a guess that has worked well so far. check_mintime_to_builder(self, apg_job, 120) # If there's a job that will complete within a shorter time then # we expect to be given that time frame. build, bq = find_job(self, 'postgres') set_remaining_time_for_running_job(bq, 30) check_mintime_to_builder(self, apg_job, 30) # Disable the native x86 builders. for builder in self.builders[(self.x86_proc.id, False)]: builder.builderok = False # No builders capable of running the job at hand are available now. self.assertEqual(0, builders_for_job(apg_job)) # The "minimum time to builder" estimation logic is not aware of this # though. check_mintime_to_builder(self, apg_job, 0) # The following job can only run on a native builder. job = self.makeCustomBuildQueue( estimated_duration=111, sourcename=u'xxr-gftp', score=1055, virtualized=False) self.builds.append(job.specific_build) # Disable all native builders. for builder in self.builders[(None, False)]: builder.builderok = False # All native builders are disabled now. No builders capable of # running the job at hand are available. self.assertEqual(0, builders_for_job(job)) # The "minimum time to builder" estimation logic is not aware of the # fact that no builders capable of running the job are available. check_mintime_to_builder(self, job, 0)
def test_pending_jobs_only(self): # Let's see the assertion fail for a job that's not pending any more. assign_to_builder(self, 'gedit', 1, 'hppa') gedit_build, gedit_job = find_job(self, 'gedit', 'hppa') self.assertRaises(AssertionError, gedit_job.getEstimatedJobStartTime)
def disabled_test_min_time_to_next_builder(self): """When is the next builder capable of running the job at the head of the queue becoming available?""" # XXX AaronBentley 2010-03-19 bug=541914: Fails spuriously # One of four builders for the 'apg' build is immediately available. apg_build, apg_job = find_job(self, 'apg', 'hppa') check_mintime_to_builder(self, apg_job, 0) # Assign the postgres job to a builder. assign_to_builder(self, 'postgres', 1, 'hppa') # Now one builder is gone. But there should still be a builder # immediately available. check_mintime_to_builder(self, apg_job, 0) assign_to_builder(self, 'flex', 2, 'hppa') check_mintime_to_builder(self, apg_job, 0) assign_to_builder(self, 'bison', 3, 'hppa') # Now that no builder is immediately available, the shortest # remaing build time (based on the estimated duration) is returned: # 660 seconds # This is equivalent to the 'bison' job's estimated duration. check_mintime_to_builder(self, apg_job, 660) # Now we pretend that the 'postgres' started 13 minutes ago. Its # remaining execution time should be 2 minutes = 120 seconds and # it now becomes the job whose builder becomes available next. build, bq = find_job(self, 'postgres', 'hppa') set_remaining_time_for_running_job(bq, 120) check_mintime_to_builder(self, apg_job, 120) # What happens when jobs overdraw the estimated duration? Let's # pretend the 'flex' job started 14 minutes ago. build, bq = find_job(self, 'flex', 'hppa') set_remaining_time_for_running_job(bq, -60) # In such a case we assume that the job will complete within 2 # minutes, this is a guess that has worked well so far. check_mintime_to_builder(self, apg_job, 120) # If there's a job that will complete within a shorter time then # we expect to be given that time frame. build, bq = find_job(self, 'postgres', 'hppa') set_remaining_time_for_running_job(bq, 30) check_mintime_to_builder(self, apg_job, 30) # Disable the native hppa builders. for builder in self.builders[(self.hppa_proc.id, False)]: builder.builderok = False # No builders capable of running the job at hand are available now. self.assertEqual(0, builders_for_job(apg_job)) check_mintime_to_builder(self, apg_job, 0) # Let's add a processor-independent job to the mix. job = self.makeCustomBuildQueue( virtualized=False, estimated_duration=22, sourcename='my-recipe-digikam', score=9999) # There are still builders available for the processor-independent # job. self.assertEqual(6, builders_for_job(job)) # Even free ones. self.assertTrue( bq._getFreeBuildersCount(job.processor, job.virtualized) > 0, "Builders are immediately available for processor-independent " "jobs.") check_mintime_to_builder(self, job, 0) # Let's disable all builders. for builders in self.builders.itervalues(): for builder in builders: builder.builderok = False # There are no builders capable of running even the processor # independent jobs now. self.assertEqual(0, builders_for_job(job)) check_mintime_to_builder(self, job, 0) # Re-enable the native hppa builders. for builder in self.builders[(self.hppa_proc.id, False)]: builder.builderok = True # The builder that's becoming available next is the one that's # running the 'postgres' build. check_mintime_to_builder(self, apg_job, 30) # Make sure we'll find an x86 builder as well. builder = self.builders[(self.x86_proc.id, False)][0] builder.builderok = True # Now this builder is the one that becomes available next (29 minutes # remaining build time). assign_to_builder(self, 'gcc', 1, '386') build, bq = find_job(self, 'gcc', '386') set_remaining_time_for_running_job(bq, 29) check_mintime_to_builder(self, apg_job, 29) # Make a second, idle x86 builder available. builder = self.builders[(self.x86_proc.id, False)][1] builder.builderok = True # That builder should be available immediately since it's idle. check_mintime_to_builder(self, apg_job, 0)
def test_no_builder_no_estimate(self): # No dispatch estimate is provided in the absence of builders that # can run the job of interest (JOI). disable_builders(self, '386', True) vim_build, vim_job = find_job(self, 'vim', '386') check_estimate(self, vim_job, None)
def setUp(self): """Add more processor-independent jobs to the mix, make the '386' jobs virtual. 3, gedit, p: hppa, v:False e:0:01:00 *** s: 1003 4, gedit, p: 386, v: True e:0:02:00 *** s: 1006 5, firefox, p: hppa, v:False e:0:03:00 *** s: 1009 6, firefox, p: 386, v: True e:0:04:00 *** s: 1012 7, apg, p: hppa, v:False e:0:05:00 *** s: 1015 9, vim, p: hppa, v:False e:0:07:00 *** s: 1021 10, vim, p: 386, v: True e:0:08:00 *** s: 1024 8, apg, p: 386, v: True e:0:06:00 *** s: 1024 19, xxr-aptitude, p: None, v:False e:0:05:32 *** s: 1025 11, gcc, p: hppa, v:False e:0:09:00 *** s: 1027 12, gcc, p: 386, v: True e:0:10:00 *** s: 1030 13, bison, p: hppa, v:False e:0:11:00 *** s: 1033 14, bison, p: 386, v: True e:0:12:00 *** s: 1036 15, flex, p: hppa, v:False e:0:13:00 *** s: 1039 16, flex, p: 386, v: True e:0:14:00 *** s: 1042 23, xxr-apt-build, p: None, v: True e:0:12:56 *** s: 1043 22, xxr-cron-apt, p: None, v: True e:0:11:05 *** s: 1043 26, xxr-cupt, p: None, v: True e:0:18:30 *** s: 1044 25, xxr-apt, p: None, v: True e:0:16:38 *** s: 1044 24, xxr-debdelta, p: None, v: True e:0:14:47 *** s: 1044 17, postgres, p: hppa, v:False e:0:15:00 *** s: 1045 18, postgres, p: 386, v: True e:0:16:00 *** s: 1048 21, xxr-daptup, p: None, v: True e:0:09:14 *** s: 1051 20, xxr-auto-apt, p: None, v:False e:0:07:23 *** s: 1053 p=processor, v=virtualized, e=estimated_duration, s=score """ super(TestJobDispatchTimeEstimation, self).setUp() job = self.makeCustomBuildQueue( virtualized=False, estimated_duration=332, sourcename=u'xxr-aptitude', score=1025) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( virtualized=False, estimated_duration=443, sourcename=u'xxr-auto-apt', score=1053) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=554, sourcename=u'xxr-daptup', score=1051) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=665, sourcename=u'xxr-cron-apt', score=1043) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=776, sourcename=u'xxr-apt-build', score=1043) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=887, sourcename=u'xxr-debdelta', score=1044) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=998, sourcename=u'xxr-apt', score=1044) self.builds.append(job.specific_build) job = self.makeCustomBuildQueue( estimated_duration=1110, sourcename=u'xxr-cupt', score=1044) self.builds.append(job.specific_build) # Assign the same score to the '386' vim and apg build jobs. _apg_build, apg_job = find_job(self, 'apg', '386') apg_job.lastscore = 1024 # Also, toggle the 'virtualized' flag for all '386' jobs. for build in self.builds: bq = build.buildqueue_record if bq.processor == self.x86_proc: removeSecurityProxy(bq).virtualized = True