#!/usr/bin/env expect ############################################################################ # Purpose: Test of Slurm functionality # Test some valid combinations of srun --gpu and non-GPU GRES options # # Output: "TEST: #.#" followed by "SUCCESS" if test was successful, OR # "FAILURE: ..." otherwise with an explanation of the failure, OR # anything else indicates a failure mode that must be investigated. ############################################################################ # Copyright (C) 2018 SchedMD LLC # Written by Morris Jette # # 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., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ############################################################################ source ./globals set test_id "39.12" set exit_code 0 set file_in "test$test_id.input" set number_commas "\[0-9_,\]+" print_header $test_id if {[test_cons_tres]} { send_user "\nValid configuration, using select/cons_tres\n" } else { send_user "\nWARNING: This test is only compatible with select/cons_tres\n" exit 0 } if {[test_front_end]} { send_user "\nWARNING: This test is incompatible with front-end systems\n" exit $exit_code } set def_part_name [default_partition] set nb_nodes [get_node_cnt_in_part $def_part_name] if {$nb_nodes > 1} { set nb_nodes 2 } set gpu_cnt [get_gpu_count $nb_nodes] if {$gpu_cnt < 0} { send_user "\nFAILURE: Error getting GPU count\n" exit 1 } if {$gpu_cnt < 1} { send_user "\nWARNING: This test requires 1 or more GPUs per node for at least $nb_nodes nodes in the default partition\n" exit 0 } set craynetwork_count [get_craynetwork_count $nb_nodes] if {$craynetwork_count < 0} { send_user "\nFAILURE: Error getting craynetwork GRES count\n" exit 1 } if {$craynetwork_count < 1} { send_user "\nWARNING: This test requires 1 or more craynetwork GRES per node for at least $nb_nodes nodes in the default partition\n" exit 0 } set one_task_per_core [test_select_type_params "CR_ONE_TASK_PER_CORE"] get_node_config set sockets_with_gpus [get_gpu_socket_count $gpu_cnt $sockets_per_node] send_user "\nGPU count is $gpu_cnt\n" send_user "Sockets with GPUs $sockets_with_gpus\n" send_user "Sockets per node is $sockets_per_node\n" send_user "Cores per socket is $cores_per_socket\n" send_user "CPUs per socket is $cpus_per_socket\n" send_user "gres/craynetwork count is $craynetwork_count\n" send_user "CR_ONE_TASK_PER_CORE is $one_task_per_core\n" set cores_per_node [expr $sockets_per_node * $cores_per_socket] set cpus_per_node [expr $sockets_per_node * $cpus_per_socket] if {$one_task_per_core > 0} { if {$gpu_cnt > $cores_per_node} { set gpu_cnt $cores_per_node } } else { if {$gpu_cnt > $cpus_per_node} { set gpu_cnt $cpus_per_node } } set tot_gpus $gpu_cnt if {$nb_nodes > 1} { incr tot_gpus $gpu_cnt } set gpus_per_node $gpu_cnt if {$gpus_per_node > 1 && $sockets_per_node > 1} { set sockets_per_node 2 set gpus_per_socket [expr $gpus_per_node / $sockets_per_node] } else { set gpus_per_socket $gpus_per_node } set sockets_per_node [expr $gpus_per_node / $gpus_per_socket] # # Build input script file # make_bash_script $file_in "echo HOST:\$SLURMD_NODENAME CUDA_VISIBLE_DEVICES:\$CUDA_VISIBLE_DEVICES if \[ \$SLURM_PROCID -eq 0 \]; then sleep 1 $scontrol -dd show job \$SLURM_JOB_ID | grep \"GRES=\" fi exit 0" # # Test --gpus options using a subset of GPUs actually available on the node # send_user "\n\nTEST: --gpus option\n" set match_craynetwork 0 set match_gpu 0 set timeout $max_job_delay if {$tot_gpus > 1} { set use_gpus_per_job [expr $tot_gpus - 1] } else { set use_gpus_per_job $tot_gpus } set srun_pid [spawn $srun --gres=craynetwork --cpus-per-gpu=1 --gpus=$use_gpus_per_job --nodes=$nb_nodes -t1 -J "test$test_id" -l ./$file_in] expect { -re "CUDA_VISIBLE_DEVICES:($number_commas)" { incr match_gpu [cuda_count $expect_out(1,string)] exp_continue } -re "craynetwork.CNT:($number)" { if {$expect_out(1,string) == 1} { incr match_craynetwork } else { set match_craynetwork -9999 } exp_continue } timeout { send_user "\nFAILURE: srun not responding\n" slow_kill $srun_pid set exit_code 1 } eof { wait } } if {$match_craynetwork < 1} { send_user "\nFAILURE: srun --gres=craynetwork failure ($match_craynetwork < 1)\n" set exit_code 1 } set expected_gpus $use_gpus_per_job if {$match_gpu != $expected_gpus} { send_user "\nFAILURE: srun --gpus failure ($match_gpu != $expected_gpus)\n" set exit_code 1 } if {[expr $use_gpus_per_job - 2] > $nb_nodes} { send_user "\n\nTEST: --gpus option, part 2\n" set match_craynetwork 0 set match_gpu 0 incr use_gpus_per_job -2 set srun_pid [spawn $srun --gres=craynetwork:1 --cpus-per-gpu=1 --gpus=$use_gpus_per_job --nodes=$nb_nodes -t1 -J "test$test_id" -l ./$file_in] expect { -re "CUDA_VISIBLE_DEVICES:($number_commas)" { incr match_gpu [cuda_count $expect_out(1,string)] exp_continue } -re "craynetwork.CNT:($number)" { if {$expect_out(1,string) == 1} { incr match_craynetwork } else { set match_craynetwork -9999 } exp_continue } timeout { send_user "\nFAILURE: srun not responding\n" slow_kill $srun_pid set exit_code 1 } eof { wait } } if {$match_craynetwork < 1} { send_user "\nFAILURE: srun --gres=craynetwork failure ($match_craynetwork < 1)\n" set exit_code 1 } set expected_gpus $use_gpus_per_job if {$match_gpu != $expected_gpus} { send_user "\nFAILURE: srun --gpus failure ($match_gpu != $expected_gpus)\n" set exit_code 1 } } # # Test --gpus-per-node options using a subset of GPUs actually available on the node # send_user "\n\nTEST: --gpus-per-node option\n" set match_craynetwork 0 set match_gpu 0 if {$gpus_per_node > 1} { set use_gpus_per_node [expr $gpus_per_node - 1] } else { set use_gpus_per_node $gpus_per_node } set srun_pid [spawn $srun --gres=craynetwork --cpus-per-gpu=1 --gpus-per-node=$use_gpus_per_node --nodes=$nb_nodes -t1 -J "test$test_id" -l ./$file_in] expect { -re "CUDA_VISIBLE_DEVICES:($number_commas)" { incr match_gpu [cuda_count $expect_out(1,string)] exp_continue } -re "craynetwork.CNT:($number)" { if {$expect_out(1,string) == 1} { incr match_craynetwork } else { set match_craynetwork -9999 } exp_continue } timeout { send_user "\nFAILURE: srun not responding\n" slow_kill $srun_pid set exit_code 1 } eof { wait } } if {$match_craynetwork < 1} { send_user "\nFAILURE: srun --gres=craynetwork failure ($match_craynetwork < 1)\n" set exit_code 1 } set expected_gpus [expr $use_gpus_per_node * $nb_nodes] if {$match_gpu != $expected_gpus} { send_user "\nFAILURE: srun --gpus-per-node failure ($match_gpu != $expected_gpus)\n" set exit_code 1 } # # Test --gpus-per-socket options using a subset of GPUs actually available on the node # send_user "\n\nTEST: --gpus-per-socket option\n" set match_craynetwork 0 set match_gpu 0 if {$sockets_with_gpus > 1} { set cpus_per_task $cpus_per_socket } else { set cpus_per_task 1 } # Every node requires at least 1 GPU if {$use_gpus_per_job < $nb_nodes} { set nb_nodes $use_gpus_per_job } set srun_pid [spawn $srun --gres=craynetwork --gpus-per-socket=1 --sockets-per-node=$sockets_with_gpus --nodes=$nb_nodes --ntasks=$nb_nodes --cpus-per-task=$cpus_per_task -t1 -J "test$test_id" -l ./$file_in] expect { -re "CUDA_VISIBLE_DEVICES:($number_commas)" { incr match_gpu [cuda_count $expect_out(1,string)] exp_continue } -re "craynetwork.CNT:($number)" { if {$expect_out(1,string) == 1} { incr match_craynetwork } else { set match_craynetwork -9999 } exp_continue } timeout { send_user "\nFAILURE: srun not responding\n" slow_kill $srun_pid set exit_code 1 } eof { wait } } if {$match_craynetwork < 1} { send_user "\nFAILURE: srun --gres=craynetwork failure ($match_craynetwork < 1)\n" set exit_code 1 } set expected_gpus [expr $sockets_with_gpus * $nb_nodes] if {$match_gpu != $expected_gpus} { send_user "\nFAILURE: srun --gpus-per-socket failure ($match_gpu != $expected_gpus)\n" set exit_code 1 } # # Test --gpus-per-task options using a subset of GPUs actually available on the node # send_user "\n\nTEST: --gpus-per-task option\n" set match_craynetwork 0 set match_gpu 0 if {$gpu_cnt > 1} { set use_gpus_per_node [expr $gpu_cnt - 1] } else { set use_gpus_per_node $gpu_cnt } set srun_pid [spawn $srun --gres=craynetwork --cpus-per-gpu=1 --gpus-per-task=1 -N1 --ntasks=$use_gpus_per_node -t1 -J "test$test_id" -l ./$file_in] expect { -re "CUDA_VISIBLE_DEVICES:($number_commas)" { incr match_gpu [cuda_count $expect_out(1,string)] exp_continue } -re "craynetwork.CNT:($number)" { if {$expect_out(1,string) == 1} { incr match_craynetwork } else { set match_craynetwork -9999 } exp_continue } timeout { send_user "\nFAILURE: srun not responding\n" slow_kill $srun_pid set exit_code 1 } eof { wait } } if {$match_craynetwork < 1} { send_user "\nFAILURE: srun --gres=craynetwork failure ($match_craynetwork < 1)\n" set exit_code 1 } set expected_gpus [expr $use_gpus_per_node * $use_gpus_per_node] if {$match_gpu != $expected_gpus} { send_user "\nFAILURE: srun --gpus-per-task failure ($match_gpu != $expected_gpus)\n" set exit_code 1 } if {$exit_code == 0} { exec $bin_rm -f $file_in send_user "\nSUCCESS\n" } exit $exit_code