#!/usr/bin/env expect ############################################################################ # Purpose: Test of Slurm functionality # Test that the OverSubscribe option in partitions is being enforced. ############################################################################ # Copyright (C) 2014 SchedMD LLC # Written by Nathan Yee # # This file is part of Slurm, a resource management program. # For details, see . # Please also read the included file: DISCLAIMER. # # Slurm is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # Slurm is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along # with Slurm; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ############################################################################ source ./globals set file_in "test$test_id\_sc" set test_part_1 "test$test_id\_part_1" set test_part_2 "test$test_id\_part_2" set test_part_3 "test$test_id\_part_3" set num_jobs 0 set cr_core 0 set cr_cpu 0 set cr_socket 0 set cpu_cnt 0 set socket_cnt 0 set thread_cnt 0 set oversubscribe_j_cnt 2 set job_id 0 set node_name "" set exit_code 0 if {[test_linear]} { skip "Test is not compatible with a config of SelectType=select/linear" } if {[is_super_user] == 0} { skip "This test can't be run except as SlurmUser" } if {[test_select_type_params "CR_SOCKET"]} { skip "This test is incompatible with CR_SOCKET allocations" } if {[test_select_type_params "CR_CORE"]} { set cr_core 1 } if {[test_select_type_params "CR_CPU"]} { set cr_cpu 1 } log_user 0 set job_mem_opt "--comment=no_mem" spawn -noecho $bin_bash -c "exec $scontrol show config | $bin_grep SelectTypeParameters" expect { -re "MEMORY" { set job_mem_opt "--mem-per-cpu=4" exp_continue } eof { wait } } log_user 1 proc cr_core_cpu { node } { global cr_cpu cr_core core_cnt socket_cnt scontrol number exit_code global cpu_cnt thread_cnt log_user 0 spawn $scontrol show node $node expect { -re "CoresPerSocket=($number)" { set core_cnt $expect_out(1,string) exp_continue } -re "CPUTot=($number)" { set cpu_cnt $expect_out(1,string) exp_continue } -re "Sockets=($number)" { set socket_cnt $expect_out(1,string) exp_continue } -re "ThreadsPerCore=($number)" { set thread_cnt $expect_out(1,string) exp_continue } timeout { log_error "scontrol is not responding" set exit_code 1 } eof { wait } } log_user 1 if { $cr_cpu == 1 } { return [expr $cpu_cnt / $thread_cnt] } elseif { $cr_core == 1 } { return [expr $core_cnt * $socket_cnt] } else { log_error "an error occurred when getting the cpu or core count" set exit_code 1 } } # Get default_queue_depth to see how many jobs will start at one time proc default_queue_depth { } { global scontrol exit_coode number set depth 100 log_user 0 spawn $scontrol show config expect { -re "default_queue_depth=($number)" { set depth $expect_out(1,string) exp_continue } timeout { log_error "scontrol is not responding" set exit_code 1 } eof { wait } } log_user 1 return $depth } proc create_part {part oversubscribe node} { global scontrol exit_code spawn $scontrol create partitionname=$part OverSubscribe=$oversubscribe nodes=$node expect { timeout { log_error "scontrol is not responding" set exit_code 1 } eof { wait } } } proc delete_part {part} { global scontrol exit_code spawn $scontrol delete partitionname=$part expect { timeout { log_error "scontrol is not responding" set exit_code 1 } eof { wait } } } proc sub_job { job oversubscribe part } { global sbatch file_in number job_id exit_code job_mem_opt set job_id 0 if { $oversubscribe } { spawn $sbatch -a$job -t1 $job_mem_opt -p$part --oversubscribe -o/dev/null $file_in expect { -re "Submitted batch job ($number)" { set job_id $expect_out(1,string) exp_continue } timeout { log_error "sbatch is not responding" set exit_code 1 } eof { wait } } } else { spawn $sbatch -a$job -t1 $job_mem_opt -p$part -o/dev/null $file_in expect { -re "Submitted batch job ($number)" { set job_id $expect_out(1,string) exp_continue } timeout { log_error "sbatch is not responding" set exit_code 1 } eof { wait } } } if {$job_id == 0} { log_error "sbatch did not submit job" set exit_code 1 } } proc check_job { exp_num_jobs } { global squeue job_id num_jobs file_in exit_code # Wait a bit for the job to start if {[wait_for_job ${job_id}_0 "RUNNING"] != 0} { log_error "Error waiting for job ${job_id}_0 to start" cancel_job ${job_id}_0 set exit_code 1 } set job_cnt 0 # If gang scheduling is configured, some jobs will be suspended spawn $squeue --job=$job_id --state=RUNNING,SUSPENDED -Oname --noheader expect { -re "$file_in" { incr job_cnt 1 exp_continue } timeout { log_error "squeue is not responding" set exit_code 1 } eof { wait } } if { $job_cnt != $exp_num_jobs } { log_error "The number of possible jobs that could run were not reached ($job_cnt != $exp_num_jobs). This could be due to memory or other limits." set exit_code 1 } } proc check_part { } { global scontrol test_part_1 test_part_2 test_part_3 exit_code set found 0 set part_name "" log_user 0 spawn $scontrol -a show part expect { -re "PartitionName=($test_part_1|$test_part_2|$test_part_3)" { set found 1 set part_name $expect_out(1,string) exp_continue } timeout { log_error "scontrol not responding" set exit_code 1 } eof { wait } } log_user 1 if {$found == 1} { log_warn "Partition $part_name already exists" delete_part $test_part_1 delete_part $test_part_2 delete_part $test_part_3 } } ##################################Test Begins################################## # Check that partition names have not been used check_part # Remove any vestigial partitions or scripts exec $bin_rm -f $file_in make_bash_script $file_in "sleep 10" spawn $sbatch -N1 -t1 -o/dev/null --exclusive $file_in expect { -re "Submitted batch job ($number)" { set job_id $expect_out(1,string) exp_continue } timeout { log_error "sbatch is not reponding" set exit_code 1 } eof { wait } } if {$job_id == 0} { fail "sbatch did not submit job" } # Wait a bit for job to start if {[wait_for_job $job_id "RUNNING"] != 0} { log_error "Error waiting for job $job_id to start" cancel_job $job_id set exit_code 1 } # Identify node to use for testing set got_node 0 spawn $scontrol show job $job_id expect { -re "NodeList=($re_word_str)" { set node_name $expect_out(1,string) set got_node 1 exp_continue } timeout { log_error "scontrol is not responding" set exit_code 1 } eof { wait } } if {$got_node != 1} { fail "No node was set for job" } cancel_job $job_id #################################### # # Test partition with oversubscribe=NO # #################################### log_info "Test partition with oversubscribe=NO" # Determine the number of cores or CPUs set num_jobs [cr_core_cpu $node_name] set job_start [default_queue_depth] if { $num_jobs >= $job_start } { skip "default_queue_depth less than core count ($num_jobs < $job_start), can not run this test" } # Create first test partition create_part $test_part_1 NO $node_name # Submit a job with oversubscribe sub_job "0-$num_jobs" 1 $test_part_1 # Check that the correct number of jobs are running check_job $num_jobs cancel_job $job_id # Submit a job without oversubscribe sub_job "0-$num_jobs" 0 $test_part_1 check_job $num_jobs cancel_job $job_id delete_part $test_part_1 #################################### # # Test partition with oversubscribe=YES:2 # #################################### set new_job_limit [expr $num_jobs * 2] if { [test_gang] == 1 } { log_info "Test partition with oversubscribe=YES:2 incompatible with gang scheduling" } elseif { $new_job_limit >= $job_start } { skip "default_queue_depth less than desired job count ($new_job_limit < $job_start), can not run oversubscribe=YES:2" } else { log_info "Test partition with oversubscribe=YES:2" # Make a new partition with oversubscribe=yes:2 create_part $test_part_2 "YES:$oversubscribe_j_cnt" $node_name # Submit a job with oversubscribe (expect 2 jobs per core/CPU) sub_job "0-$new_job_limit" 1 $test_part_2 check_job $new_job_limit cancel_job $job_id # Submit a job without oversubscribe (expect 1 job per core/CPU) sub_job "0-$num_jobs" 0 $test_part_2 check_job $num_jobs cancel_job $job_id delete_part $test_part_2 } ######################################## # # Test partition with oversubscribe=EXCLUSIVE # ######################################## log_info "Test partition with oversubscribe=EXCLUSIVE" # Make a new partition with oversubscribe=EXCLUSIVE create_part $test_part_3 "EXCLUSIVE" $node_name # Submit a job with oversubscribe (expected 1 job per node) sub_job "0-$num_jobs" 1 $test_part_3 check_job 1 cancel_job $job_id # Submit a job with oversubscribe (expected 1 job per node) sub_job "0-$num_jobs" 0 $test_part_3 check_job 1 cancel_job $job_id delete_part $test_part_3 if {$exit_code == 0} { exec $bin_rm -f $file_in } else { fail "Test failed due to previous errors" }