diff --git a/Makefile.am b/Makefile.am index c1a698b78f6eb78418057b1956f3e64bd0fa87dd..46161d91255437a3d0ffb31a69d8b53a41abf17b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,6 +10,7 @@ EXTRA_DIST = \ etc/cgroup_allowed_devices_file.conf.example \ etc/init.d.slurm.in \ etc/init.d.slurmdbd.in \ + etc/layouts.d.power.conf.example \ etc/slurm.conf.example \ etc/slurm.epilog.clean \ etc/slurmctld.service.in \ diff --git a/Makefile.in b/Makefile.in index 082f03cc5886152ce68840139f79b50cdb59b910..929109923bf67e99d6289f362167985849d70089 100644 --- a/Makefile.in +++ b/Makefile.in @@ -540,6 +540,7 @@ EXTRA_DIST = \ etc/cgroup_allowed_devices_file.conf.example \ etc/init.d.slurm.in \ etc/init.d.slurmdbd.in \ + etc/layouts.d.power.conf.example \ etc/slurm.conf.example \ etc/slurm.epilog.clean \ etc/slurmctld.service.in \ diff --git a/configure b/configure index 1c987dc149163a74b05538f2e9c240fcaf33cd9f..1fd83872fc79b014865665ecb223a631b5a6d7e2 100755 --- a/configure +++ b/configure @@ -24538,7 +24538,7 @@ fi -ac_config_files="$ac_config_files Makefile config.xml auxdir/Makefile contribs/Makefile contribs/cray/Makefile contribs/lua/Makefile contribs/mic/Makefile contribs/pam/Makefile contribs/pam_slurm_adopt/Makefile contribs/perlapi/Makefile contribs/perlapi/libslurm/Makefile contribs/perlapi/libslurm/perl/Makefile.PL contribs/perlapi/libslurmdb/Makefile contribs/perlapi/libslurmdb/perl/Makefile.PL contribs/torque/Makefile contribs/phpext/Makefile contribs/phpext/slurm_php/config.m4 contribs/sgather/Makefile contribs/sgi/Makefile contribs/sjobexit/Makefile contribs/slurmdb-direct/Makefile contribs/pmi2/Makefile doc/Makefile doc/man/Makefile doc/man/man1/Makefile doc/man/man3/Makefile doc/man/man5/Makefile doc/man/man8/Makefile doc/html/Makefile doc/html/configurator.html doc/html/configurator.easy.html etc/cgroup.release_common.example etc/init.d.slurm etc/init.d.slurmdbd etc/slurmctld.service etc/slurmd.service etc/slurmdbd.service src/Makefile src/api/Makefile src/common/Makefile src/db_api/Makefile src/layouts/Makefile src/layouts/unit/Makefile src/database/Makefile src/sacct/Makefile src/sacctmgr/Makefile src/sreport/Makefile src/salloc/Makefile src/sbatch/Makefile src/sbcast/Makefile src/sattach/Makefile src/scancel/Makefile src/scontrol/Makefile src/sdiag/Makefile src/sinfo/Makefile src/slurmctld/Makefile src/slurmd/Makefile src/slurmd/common/Makefile src/slurmd/slurmd/Makefile src/slurmd/slurmstepd/Makefile src/slurmdbd/Makefile src/smap/Makefile src/smd/Makefile src/sprio/Makefile src/squeue/Makefile src/srun/Makefile src/srun/libsrun/Makefile src/srun_cr/Makefile src/sshare/Makefile src/sstat/Makefile src/strigger/Makefile src/sview/Makefile src/plugins/Makefile src/plugins/accounting_storage/Makefile src/plugins/accounting_storage/common/Makefile src/plugins/accounting_storage/filetxt/Makefile src/plugins/accounting_storage/mysql/Makefile src/plugins/accounting_storage/none/Makefile src/plugins/accounting_storage/slurmdbd/Makefile src/plugins/acct_gather_energy/Makefile src/plugins/acct_gather_energy/cray/Makefile src/plugins/acct_gather_energy/rapl/Makefile src/plugins/acct_gather_energy/ipmi/Makefile src/plugins/acct_gather_energy/none/Makefile src/plugins/acct_gather_infiniband/Makefile src/plugins/acct_gather_infiniband/ofed/Makefile src/plugins/acct_gather_infiniband/none/Makefile src/plugins/acct_gather_filesystem/Makefile src/plugins/acct_gather_filesystem/lustre/Makefile src/plugins/acct_gather_filesystem/none/Makefile src/plugins/acct_gather_profile/Makefile src/plugins/acct_gather_profile/hdf5/Makefile src/plugins/acct_gather_profile/hdf5/sh5util/Makefile src/plugins/acct_gather_profile/none/Makefile src/plugins/auth/Makefile src/plugins/auth/authd/Makefile src/plugins/auth/munge/Makefile src/plugins/auth/none/Makefile src/plugins/burst_buffer/Makefile src/plugins/burst_buffer/common/Makefile src/plugins/burst_buffer/cray/Makefile src/plugins/burst_buffer/generic/Makefile src/plugins/checkpoint/Makefile src/plugins/checkpoint/aix/Makefile src/plugins/checkpoint/blcr/Makefile src/plugins/checkpoint/blcr/cr_checkpoint.sh src/plugins/checkpoint/blcr/cr_restart.sh src/plugins/checkpoint/none/Makefile src/plugins/checkpoint/ompi/Makefile src/plugins/checkpoint/poe/Makefile src/plugins/core_spec/Makefile src/plugins/core_spec/cray/Makefile src/plugins/core_spec/none/Makefile src/plugins/crypto/Makefile src/plugins/crypto/munge/Makefile src/plugins/crypto/openssl/Makefile src/plugins/ext_sensors/Makefile src/plugins/ext_sensors/rrd/Makefile src/plugins/ext_sensors/none/Makefile src/plugins/gres/Makefile src/plugins/gres/gpu/Makefile src/plugins/gres/nic/Makefile src/plugins/gres/mic/Makefile src/plugins/jobacct_gather/Makefile src/plugins/jobacct_gather/common/Makefile src/plugins/jobacct_gather/linux/Makefile src/plugins/jobacct_gather/aix/Makefile src/plugins/jobacct_gather/cgroup/Makefile src/plugins/jobacct_gather/none/Makefile src/plugins/jobcomp/Makefile src/plugins/jobcomp/elasticsearch/Makefile src/plugins/jobcomp/filetxt/Makefile src/plugins/jobcomp/none/Makefile src/plugins/jobcomp/script/Makefile src/plugins/jobcomp/mysql/Makefile src/plugins/job_container/Makefile src/plugins/job_container/cncu/Makefile src/plugins/job_container/none/Makefile src/plugins/job_submit/Makefile src/plugins/job_submit/all_partitions/Makefile src/plugins/job_submit/cnode/Makefile src/plugins/job_submit/cray/Makefile src/plugins/job_submit/defaults/Makefile src/plugins/job_submit/logging/Makefile src/plugins/job_submit/lua/Makefile src/plugins/job_submit/partition/Makefile src/plugins/job_submit/pbs/Makefile src/plugins/job_submit/require_timelimit/Makefile src/plugins/job_submit/throttle/Makefile src/plugins/launch/Makefile src/plugins/launch/aprun/Makefile src/plugins/launch/poe/Makefile src/plugins/launch/runjob/Makefile src/plugins/launch/slurm/Makefile src/plugins/power/Makefile src/plugins/power/common/Makefile src/plugins/power/cray/Makefile src/plugins/power/none/Makefile src/plugins/preempt/Makefile src/plugins/preempt/job_prio/Makefile src/plugins/preempt/none/Makefile src/plugins/preempt/partition_prio/Makefile src/plugins/preempt/qos/Makefile src/plugins/priority/Makefile src/plugins/priority/basic/Makefile src/plugins/priority/multifactor/Makefile src/plugins/proctrack/Makefile src/plugins/proctrack/aix/Makefile src/plugins/proctrack/cray/Makefile src/plugins/proctrack/cgroup/Makefile src/plugins/proctrack/pgid/Makefile src/plugins/proctrack/linuxproc/Makefile src/plugins/proctrack/sgi_job/Makefile src/plugins/proctrack/lua/Makefile src/plugins/route/Makefile src/plugins/route/default/Makefile src/plugins/route/topology/Makefile src/plugins/sched/Makefile src/plugins/sched/backfill/Makefile src/plugins/sched/builtin/Makefile src/plugins/sched/hold/Makefile src/plugins/sched/wiki/Makefile src/plugins/sched/wiki2/Makefile src/plugins/select/Makefile src/plugins/select/alps/Makefile src/plugins/select/alps/libalps/Makefile src/plugins/select/alps/libemulate/Makefile src/plugins/select/bluegene/Makefile src/plugins/select/bluegene/ba/Makefile src/plugins/select/bluegene/ba_bgq/Makefile src/plugins/select/bluegene/bl/Makefile src/plugins/select/bluegene/bl_bgq/Makefile src/plugins/select/bluegene/sfree/Makefile src/plugins/select/cons_res/Makefile src/plugins/select/cray/Makefile src/plugins/select/linear/Makefile src/plugins/select/other/Makefile src/plugins/select/serial/Makefile src/plugins/slurmctld/Makefile src/plugins/slurmctld/nonstop/Makefile src/plugins/slurmd/Makefile src/plugins/switch/Makefile src/plugins/switch/cray/Makefile src/plugins/switch/generic/Makefile src/plugins/switch/none/Makefile src/plugins/switch/nrt/Makefile src/plugins/switch/nrt/libpermapi/Makefile src/plugins/mpi/Makefile src/plugins/mpi/mpich1_p4/Makefile src/plugins/mpi/mpich1_shmem/Makefile src/plugins/mpi/mpichgm/Makefile src/plugins/mpi/mpichmx/Makefile src/plugins/mpi/mvapich/Makefile src/plugins/mpi/lam/Makefile src/plugins/mpi/none/Makefile src/plugins/mpi/openmpi/Makefile src/plugins/mpi/pmi2/Makefile src/plugins/task/Makefile src/plugins/task/affinity/Makefile src/plugins/task/cgroup/Makefile src/plugins/task/cray/Makefile src/plugins/task/none/Makefile src/plugins/topology/Makefile src/plugins/topology/3d_torus/Makefile src/plugins/topology/hypercube/Makefile src/plugins/topology/node_rank/Makefile src/plugins/topology/none/Makefile src/plugins/topology/tree/Makefile testsuite/Makefile testsuite/expect/Makefile testsuite/slurm_unit/Makefile testsuite/slurm_unit/api/Makefile testsuite/slurm_unit/api/manual/Makefile testsuite/slurm_unit/common/Makefile" +ac_config_files="$ac_config_files Makefile config.xml auxdir/Makefile contribs/Makefile contribs/cray/Makefile contribs/lua/Makefile contribs/mic/Makefile contribs/pam/Makefile contribs/pam_slurm_adopt/Makefile contribs/perlapi/Makefile contribs/perlapi/libslurm/Makefile contribs/perlapi/libslurm/perl/Makefile.PL contribs/perlapi/libslurmdb/Makefile contribs/perlapi/libslurmdb/perl/Makefile.PL contribs/torque/Makefile contribs/phpext/Makefile contribs/phpext/slurm_php/config.m4 contribs/sgather/Makefile contribs/sgi/Makefile contribs/sjobexit/Makefile contribs/slurmdb-direct/Makefile contribs/pmi2/Makefile doc/Makefile doc/man/Makefile doc/man/man1/Makefile doc/man/man3/Makefile doc/man/man5/Makefile doc/man/man8/Makefile doc/html/Makefile doc/html/configurator.html doc/html/configurator.easy.html etc/cgroup.release_common.example etc/init.d.slurm etc/init.d.slurmdbd etc/slurmctld.service etc/slurmd.service etc/slurmdbd.service src/Makefile src/api/Makefile src/common/Makefile src/db_api/Makefile src/layouts/Makefile src/layouts/unit/Makefile src/layouts/power/Makefile src/database/Makefile src/sacct/Makefile src/sacctmgr/Makefile src/sreport/Makefile src/salloc/Makefile src/sbatch/Makefile src/sbcast/Makefile src/sattach/Makefile src/scancel/Makefile src/scontrol/Makefile src/sdiag/Makefile src/sinfo/Makefile src/slurmctld/Makefile src/slurmd/Makefile src/slurmd/common/Makefile src/slurmd/slurmd/Makefile src/slurmd/slurmstepd/Makefile src/slurmdbd/Makefile src/smap/Makefile src/smd/Makefile src/sprio/Makefile src/squeue/Makefile src/srun/Makefile src/srun/libsrun/Makefile src/srun_cr/Makefile src/sshare/Makefile src/sstat/Makefile src/strigger/Makefile src/sview/Makefile src/plugins/Makefile src/plugins/accounting_storage/Makefile src/plugins/accounting_storage/common/Makefile src/plugins/accounting_storage/filetxt/Makefile src/plugins/accounting_storage/mysql/Makefile src/plugins/accounting_storage/none/Makefile src/plugins/accounting_storage/slurmdbd/Makefile src/plugins/acct_gather_energy/Makefile src/plugins/acct_gather_energy/cray/Makefile src/plugins/acct_gather_energy/rapl/Makefile src/plugins/acct_gather_energy/ipmi/Makefile src/plugins/acct_gather_energy/none/Makefile src/plugins/acct_gather_infiniband/Makefile src/plugins/acct_gather_infiniband/ofed/Makefile src/plugins/acct_gather_infiniband/none/Makefile src/plugins/acct_gather_filesystem/Makefile src/plugins/acct_gather_filesystem/lustre/Makefile src/plugins/acct_gather_filesystem/none/Makefile src/plugins/acct_gather_profile/Makefile src/plugins/acct_gather_profile/hdf5/Makefile src/plugins/acct_gather_profile/hdf5/sh5util/Makefile src/plugins/acct_gather_profile/none/Makefile src/plugins/auth/Makefile src/plugins/auth/authd/Makefile src/plugins/auth/munge/Makefile src/plugins/auth/none/Makefile src/plugins/burst_buffer/Makefile src/plugins/burst_buffer/common/Makefile src/plugins/burst_buffer/cray/Makefile src/plugins/burst_buffer/generic/Makefile src/plugins/checkpoint/Makefile src/plugins/checkpoint/aix/Makefile src/plugins/checkpoint/blcr/Makefile src/plugins/checkpoint/blcr/cr_checkpoint.sh src/plugins/checkpoint/blcr/cr_restart.sh src/plugins/checkpoint/none/Makefile src/plugins/checkpoint/ompi/Makefile src/plugins/checkpoint/poe/Makefile src/plugins/core_spec/Makefile src/plugins/core_spec/cray/Makefile src/plugins/core_spec/none/Makefile src/plugins/crypto/Makefile src/plugins/crypto/munge/Makefile src/plugins/crypto/openssl/Makefile src/plugins/ext_sensors/Makefile src/plugins/ext_sensors/rrd/Makefile src/plugins/ext_sensors/none/Makefile src/plugins/gres/Makefile src/plugins/gres/gpu/Makefile src/plugins/gres/nic/Makefile src/plugins/gres/mic/Makefile src/plugins/jobacct_gather/Makefile src/plugins/jobacct_gather/common/Makefile src/plugins/jobacct_gather/linux/Makefile src/plugins/jobacct_gather/aix/Makefile src/plugins/jobacct_gather/cgroup/Makefile src/plugins/jobacct_gather/none/Makefile src/plugins/jobcomp/Makefile src/plugins/jobcomp/elasticsearch/Makefile src/plugins/jobcomp/filetxt/Makefile src/plugins/jobcomp/none/Makefile src/plugins/jobcomp/script/Makefile src/plugins/jobcomp/mysql/Makefile src/plugins/job_container/Makefile src/plugins/job_container/cncu/Makefile src/plugins/job_container/none/Makefile src/plugins/job_submit/Makefile src/plugins/job_submit/all_partitions/Makefile src/plugins/job_submit/cnode/Makefile src/plugins/job_submit/cray/Makefile src/plugins/job_submit/defaults/Makefile src/plugins/job_submit/logging/Makefile src/plugins/job_submit/lua/Makefile src/plugins/job_submit/partition/Makefile src/plugins/job_submit/pbs/Makefile src/plugins/job_submit/require_timelimit/Makefile src/plugins/job_submit/throttle/Makefile src/plugins/launch/Makefile src/plugins/launch/aprun/Makefile src/plugins/launch/poe/Makefile src/plugins/launch/runjob/Makefile src/plugins/launch/slurm/Makefile src/plugins/power/Makefile src/plugins/power/common/Makefile src/plugins/power/cray/Makefile src/plugins/power/none/Makefile src/plugins/preempt/Makefile src/plugins/preempt/job_prio/Makefile src/plugins/preempt/none/Makefile src/plugins/preempt/partition_prio/Makefile src/plugins/preempt/qos/Makefile src/plugins/priority/Makefile src/plugins/priority/basic/Makefile src/plugins/priority/multifactor/Makefile src/plugins/proctrack/Makefile src/plugins/proctrack/aix/Makefile src/plugins/proctrack/cray/Makefile src/plugins/proctrack/cgroup/Makefile src/plugins/proctrack/pgid/Makefile src/plugins/proctrack/linuxproc/Makefile src/plugins/proctrack/sgi_job/Makefile src/plugins/proctrack/lua/Makefile src/plugins/route/Makefile src/plugins/route/default/Makefile src/plugins/route/topology/Makefile src/plugins/sched/Makefile src/plugins/sched/backfill/Makefile src/plugins/sched/builtin/Makefile src/plugins/sched/hold/Makefile src/plugins/sched/wiki/Makefile src/plugins/sched/wiki2/Makefile src/plugins/select/Makefile src/plugins/select/alps/Makefile src/plugins/select/alps/libalps/Makefile src/plugins/select/alps/libemulate/Makefile src/plugins/select/bluegene/Makefile src/plugins/select/bluegene/ba/Makefile src/plugins/select/bluegene/ba_bgq/Makefile src/plugins/select/bluegene/bl/Makefile src/plugins/select/bluegene/bl_bgq/Makefile src/plugins/select/bluegene/sfree/Makefile src/plugins/select/cons_res/Makefile src/plugins/select/cray/Makefile src/plugins/select/linear/Makefile src/plugins/select/other/Makefile src/plugins/select/serial/Makefile src/plugins/slurmctld/Makefile src/plugins/slurmctld/nonstop/Makefile src/plugins/slurmd/Makefile src/plugins/switch/Makefile src/plugins/switch/cray/Makefile src/plugins/switch/generic/Makefile src/plugins/switch/none/Makefile src/plugins/switch/nrt/Makefile src/plugins/switch/nrt/libpermapi/Makefile src/plugins/mpi/Makefile src/plugins/mpi/mpich1_p4/Makefile src/plugins/mpi/mpich1_shmem/Makefile src/plugins/mpi/mpichgm/Makefile src/plugins/mpi/mpichmx/Makefile src/plugins/mpi/mvapich/Makefile src/plugins/mpi/lam/Makefile src/plugins/mpi/none/Makefile src/plugins/mpi/openmpi/Makefile src/plugins/mpi/pmi2/Makefile src/plugins/task/Makefile src/plugins/task/affinity/Makefile src/plugins/task/cgroup/Makefile src/plugins/task/cray/Makefile src/plugins/task/none/Makefile src/plugins/topology/Makefile src/plugins/topology/3d_torus/Makefile src/plugins/topology/hypercube/Makefile src/plugins/topology/node_rank/Makefile src/plugins/topology/none/Makefile src/plugins/topology/tree/Makefile testsuite/Makefile testsuite/expect/Makefile testsuite/slurm_unit/Makefile testsuite/slurm_unit/api/Makefile testsuite/slurm_unit/api/manual/Makefile testsuite/slurm_unit/common/Makefile" cat >confcache <<\_ACEOF @@ -25882,6 +25882,7 @@ do "src/db_api/Makefile") CONFIG_FILES="$CONFIG_FILES src/db_api/Makefile" ;; "src/layouts/Makefile") CONFIG_FILES="$CONFIG_FILES src/layouts/Makefile" ;; "src/layouts/unit/Makefile") CONFIG_FILES="$CONFIG_FILES src/layouts/unit/Makefile" ;; + "src/layouts/power/Makefile") CONFIG_FILES="$CONFIG_FILES src/layouts/power/Makefile" ;; "src/database/Makefile") CONFIG_FILES="$CONFIG_FILES src/database/Makefile" ;; "src/sacct/Makefile") CONFIG_FILES="$CONFIG_FILES src/sacct/Makefile" ;; "src/sacctmgr/Makefile") CONFIG_FILES="$CONFIG_FILES src/sacctmgr/Makefile" ;; diff --git a/configure.ac b/configure.ac index 16e705c24a07796e89d17aca5d53d8fbc72f475c..d43020cb622853070455f6a7e3d00b2c1a85aaf3 100644 --- a/configure.ac +++ b/configure.ac @@ -478,6 +478,7 @@ AC_CONFIG_FILES([Makefile src/db_api/Makefile src/layouts/Makefile src/layouts/unit/Makefile + src/layouts/power/Makefile src/database/Makefile src/sacct/Makefile src/sacctmgr/Makefile diff --git a/contribs/perlapi/libslurm/perl/conf.c b/contribs/perlapi/libslurm/perl/conf.c index 2d3549ff6fd9f71eb939da0f8c2816e699977e92..f11e37d4d1656bdd168e7f7d33899d8b419b6f7d 100644 --- a/contribs/perlapi/libslurm/perl/conf.c +++ b/contribs/perlapi/libslurm/perl/conf.c @@ -229,6 +229,9 @@ slurm_ctl_conf_to_hv(slurm_ctl_conf_t *conf, HV *hv) if (conf->plugstack) STORE_FIELD(hv, conf, plugstack, charp); + if (conf->power_parameters) + STORE_FIELD(hv, conf, power_parameters, charp); + STORE_FIELD(hv, conf, preempt_mode, uint16_t); if (conf->preempt_type) @@ -508,6 +511,7 @@ hv_to_slurm_ctl_conf(HV *hv, slurm_ctl_conf_t *conf) FETCH_FIELD(hv, conf, over_time_limit, uint16_t, TRUE); FETCH_FIELD(hv, conf, plugindir, charp, FALSE); FETCH_FIELD(hv, conf, plugstack, charp, FALSE); + FETCH_FIELD(hv, conf, power_parameters, charp, FALSE); FETCH_FIELD(hv, conf, preempt_mode, uint16_t, TRUE); FETCH_FIELD(hv, conf, preempt_type, charp, FALSE); FETCH_FIELD(hv, conf, priority_calc_period, uint32_t, TRUE); diff --git a/doc/man/man1/scontrol.1 b/doc/man/man1/scontrol.1 index 49f03391be0f301b52784490739ee48b7fe79bd9..e3a06f28aa2983e47157e7ef71225767b549f80a 100644 --- a/doc/man/man1/scontrol.1 +++ b/doc/man/man1/scontrol.1 @@ -344,7 +344,7 @@ contents of the slurm.conf configuration file. \fBshow\fP \fIENTITY\fP \fIID\fP Display the state of the specified entity with the specified identification. \fIENTITY\fP may be \fIaliases\fP, \fIcache\fP, \fIconfig\fP, \fIdaemons\fP, \fIfrontend\fP, -\fIjob\fP, \fInode\fP, \fIpartition\fP, \fIreservation\fP, \fIslurmd\fP, +\fIjob\fP, \fInode\fP, \fIpartition\fP, \fIpowercap\fP, \fIreservation\fP, \fIslurmd\fP, \fIstep\fP, \fItopology\fP, \fIhostlist\fP, \fIhostlistsorted\fP or \fIhostnames\fP (also \fIblock\fP or \fIsubmp\fP on BlueGene systems). @@ -430,12 +430,12 @@ system administrator (also see the \fBhold\fP command). .TP \fBupdate\fP \fISPECIFICATION\fP -Update job, step, node, partition, or reservation configuration per the -supplied specification. \fISPECIFICATION\fP is in the same format as the Slurm -configuration file and the output of the \fIshow\fP command described above. It -may be desirable to execute the \fIshow\fP command (described above) on the -specific entity you which to update, then use cut\-and\-paste tools to enter -updated configuration values to the \fIupdate\fP. Note that while most +Update job, step, node, partition, powercapping or reservation configuration per +the supplied specification. \fISPECIFICATION\fP is in the same format as the +Slurm configuration file and the output of the \fIshow\fP command described +above. It may be desirable to execute the \fIshow\fP command (described above) +on the specific entity you which to update, then use cut\-and\-paste tools to +enter updated configuration values to the \fIupdate\fP. Note that while most configuration values can be changed using this command, not all can be changed using this mechanism. In particular, the hardware configuration of a node or the physical addition or removal of nodes from the cluster may only be @@ -1209,6 +1209,17 @@ and jobs already queued may not be allocated nodes and run. See also the "Alternate" partition specification. .RE +.TP +\fBSPECIFICATIONS FOR UPDATE COMMAND, POWERCAP\fR + +.TP +\fIPowerCap\fP=<count> +Set the amount of watts the cluster is limited to. +Specify a number, "INFINITE" to enable the power capping logic without +power restriction or "0" to disable the power capping logic. +Update slurm.conf with any changes meant to be persistent across normal +restarts of slurmctld or the execution of \fBscontrol reconfig\fR. + .TP \fBSPECIFICATIONS FOR CREATE, UPDATE, AND DELETE COMMANDS, RESERVATIONS\fR .TP diff --git a/etc/layouts.d.power.conf.example b/etc/layouts.d.power.conf.example new file mode 100644 index 0000000000000000000000000000000000000000..d0d5a8e1368c4213482d555967994180a0f0258f --- /dev/null +++ b/etc/layouts.d.power.conf.example @@ -0,0 +1,7 @@ +Priority=10 +Root=Cluster + +Entity=Cluster Type=Center CurrentSumPower=0 IdleSumWatts=0 MaxSumWatts=0 Enclosed=nodes[0-199] + +Entity=nodes[0-199] Type=Node CurrentPower=0 IdleWatts=103 MaxWatts=308 DownWatts=103 PowerSaveWatts=12 + diff --git a/slurm.spec b/slurm.spec index caa208adcebe9c5fb5ec8d4a0f7717645382b1fb..c13c22ffc613189fba1356626a5b13121f6fa601 100644 --- a/slurm.spec +++ b/slurm.spec @@ -477,15 +477,16 @@ DESTDIR="$RPM_BUILD_ROOT" %__make install-contrib rm -f $RPM_BUILD_ROOT/%{_sbindir}/slurmconfgen.py %endif -install -D -m644 etc/slurm.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/slurm.conf.example install -D -m644 etc/cgroup.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup.conf.example install -D -m644 etc/cgroup_allowed_devices_file.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup_allowed_devices_file.conf.example install -D -m755 etc/cgroup.release_common.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup.release_common.example install -D -m755 etc/cgroup.release_common.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup/release_freezer install -D -m755 etc/cgroup.release_common.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup/release_cpuset install -D -m755 etc/cgroup.release_common.example ${RPM_BUILD_ROOT}%{_sysconfdir}/cgroup/release_memory -install -D -m644 etc/slurmdbd.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/slurmdbd.conf.example +install -D -m644 etc/layouts.d.power.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/layouts.d.power.conf.example +install -D -m644 etc/slurm.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/slurm.conf.example install -D -m755 etc/slurm.epilog.clean ${RPM_BUILD_ROOT}%{_sysconfdir}/slurm.epilog.clean +install -D -m644 etc/slurmdbd.conf.example ${RPM_BUILD_ROOT}%{_sysconfdir}/slurmdbd.conf.example install -D -m755 contribs/sgather/sgather ${RPM_BUILD_ROOT}%{_bindir}/sgather install -D -m755 contribs/sjstat ${RPM_BUILD_ROOT}%{_bindir}/sjstat @@ -796,13 +797,14 @@ rm -rf $RPM_BUILD_ROOT %config %{_sysconfdir}/slurm.conf.template %{_sbindir}/slurmconfgen.py %endif -%config %{_sysconfdir}/slurm.conf.example %config %{_sysconfdir}/cgroup.conf.example %config %{_sysconfdir}/cgroup_allowed_devices_file.conf.example %config %{_sysconfdir}/cgroup.release_common.example %config %{_sysconfdir}/cgroup/release_freezer %config %{_sysconfdir}/cgroup/release_cpuset %config %{_sysconfdir}/cgroup/release_memory +%config %{_sysconfdir}/layouts.d.power.conf.example +%config %{_sysconfdir}/slurm.conf.example %config %{_sysconfdir}/slurm.epilog.clean %exclude %{_mandir}/man1/sjobexit* %exclude %{_mandir}/man1/sjstat* @@ -918,6 +920,7 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/slurm/jobcomp_filetxt.so %{_libdir}/slurm/jobcomp_none.so %{_libdir}/slurm/jobcomp_script.so +%{_libdir}/slurm/layouts_power_default.so %{_libdir}/slurm/layouts_unit_default.so %if ! %{slurm_with bluegene} %{_libdir}/slurm/mpi_lam.so diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in index 1e3219973b21a045abcb49dd833310f50aa2b29b..a44d3465b4b6dcdf730d75a0fce5e36ee95378cb 100644 --- a/slurm/slurm.h.in +++ b/slurm/slurm.h.in @@ -345,6 +345,9 @@ enum job_state_reason { WAIT_QOS_JOB_LIMIT, /* QOS job limit reached */ WAIT_QOS_RESOURCE_LIMIT,/* QOS resource limit reached */ WAIT_QOS_TIME_LIMIT, /* QOS time limit reached */ + WAIT_POWER_NOT_AVAIL, /* not enough power available */ + WAIT_POWER_RESERVED, /* job is waiting for available power + because of power reservations */ WAIT_BLOCK_MAX_ERR, /* BLUEGENE Block has too many cnodes * in error state to allow more jobs. */ WAIT_BLOCK_D_ACTION, /* BLUEGENE Block is being freed, @@ -1867,6 +1870,20 @@ typedef struct step_alloc_info_msg { uint32_t step_id; /* step ID */ } step_alloc_info_msg_t; +typedef struct powercap_info_msg { + uint32_t power_cap; /* power cap value in watts */ + uint32_t power_floor; /* power floor value in watts */ + uint32_t power_change; /* power change rate limit in watts/minute */ + uint32_t min_watts; /* min consumption of the cluster in watts */ + uint32_t cur_max_watts; /* current max consumption of the cluster in + * watts */ + uint32_t adj_max_watts; /* adjusted (removing DownNodes) max consumption + * of the cluster in watts */ + uint32_t max_watts; /* max consumption of the cluster in watts */ +} powercap_info_msg_t; + +typedef struct powercap_info_msg update_powercap_msg_t; + typedef struct acct_gather_node_resp_msg { char *node_name; /* node name */ acct_gather_energy_t *energy; @@ -2153,6 +2170,7 @@ typedef struct reserve_info { char *node_list; /* list of reserved nodes or ALL */ char *partition; /* name of partition to be used */ time_t start_time; /* start time of reservation */ + uint32_t resv_watts; /* amount of power to reserve */ char *tres_str; /* list of TRES's used by reservation */ char *users; /* names of users permitted to use */ } reserve_info_t; @@ -2181,6 +2199,7 @@ typedef struct resv_desc_msg { char *node_list; /* list of reserved nodes or ALL */ char *partition; /* name of partition to be used */ time_t start_time; /* start time of reservation */ + uint32_t resv_watts; /* amount of power to reserve */ char *tres_str; /* list of TRES's used by reservation */ char *users; /* names of users permitted to use */ } resv_desc_msg_t; @@ -3880,6 +3899,45 @@ extern void slurm_print_topo_info_msg PARAMS( extern void slurm_print_topo_record PARAMS((FILE * out, topo_info_t *topo_ptr, int one_liner)); +/*****************************************************************************\ + * SLURM POWERCAPPING READ/PRINT/UPDATE FUNCTIONS +\*****************************************************************************/ + +/* + * slurm_load_powercap - issue RPC to get slurm powercapping details + * IN powercap_info_msg_pptr - place to store a pointer to the result + * RET 0 or a slurm error code + * NOTE: free the response using slurm_free_powercap_info_msg + */ +extern int slurm_load_powercap PARAMS( + (powercap_info_msg_t **powercap_info_msg_pptr)); + +/* + * slurm_free_powercap_info_msg - free the powercapping information + * response message + * IN msg - pointer to powercapping information response message + * NOTE: buffer is loaded by slurm_load_powercap. + */ +extern void slurm_free_powercap_info_msg PARAMS((powercap_info_msg_t *msg)); + +/* + * slurm_print_powercap_info_msg - output information about powercapping + * configuration based upon message as loaded using slurm_load_powercap + * IN out - file to write to + * IN powercap_info_msg_ptr - powercapping information message pointer + * IN one_liner - print as a single line if not zero + */ +extern void slurm_print_powercap_info_msg PARAMS( + (FILE * out, powercap_info_msg_t *powercap_info_msg_ptr, + int one_liner)); + +/* + * slurm_update_powercap - issue RPC to update powercapping cap + * IN powercap_msg - description of powercapping updates + * RET 0 on success, otherwise return -1 and set errno to indicate the error + */ +extern int slurm_update_powercap PARAMS((update_powercap_msg_t * powercap_msg)); + /*****************************************************************************\ * SLURM SELECT READ/PRINT/UPDATE FUNCTIONS \*****************************************************************************/ diff --git a/slurm/slurm_errno.h b/slurm/slurm_errno.h index 61aa3755c5c078f359fbea70b936df62b3903ed7..6ec4174507c41fb36e577f11b0f74bd1757d4441 100644 --- a/slurm/slurm_errno.h +++ b/slurm/slurm_errno.h @@ -193,6 +193,9 @@ enum { ESLURM_INTERCONNECT_BUSY, ESLURM_RESERVATION_EMPTY = 2080, ESLURM_INVALID_ARRAY, + ESLURM_POWER_NOT_AVAIL, + ESLURM_POWER_RESERVED, + ESLURM_INVALID_POWERCAP, ESLURM_RESERVATION_NAME_DUP, ESLURM_JOB_STARTED, ESLURM_JOB_FINISHED, diff --git a/src/api/Makefile.am b/src/api/Makefile.am index 461d8f939778cb7f2a07be162e1383d2e86fead6..d56105b6138c6afd3d774250aedc30aa8b9367ca 100644 --- a/src/api/Makefile.am +++ b/src/api/Makefile.am @@ -98,6 +98,7 @@ slurmapi_src = \ partition_info.c \ pmi_server.c \ pmi_server.h \ + powercap_info.c \ reservation_info.c \ signal.c \ slurm_get_statistics.c \ diff --git a/src/api/Makefile.in b/src/api/Makefile.in index a0e3afbb9a5bc8134fcb38c4469305dd3e9f1e91..a8cb5a29da369404703e3ec05a30dc28c6e7a116 100644 --- a/src/api/Makefile.in +++ b/src/api/Makefile.in @@ -189,7 +189,7 @@ am__objects_1 = allocate.lo allocate_msg.lo block_info.lo \ burst_buffer_info.lo cache_info.lo cancel.lo checkpoint.lo \ complete.lo config_info.lo front_end_info.lo init_msg.lo \ job_info.lo job_step_info.lo layout_info.lo license_info.lo \ - node_info.lo partition_info.lo pmi_server.lo \ + node_info.lo partition_info.lo pmi_server.lo powercap_info.lo \ reservation_info.lo signal.lo slurm_get_statistics.lo \ slurm_hostlist.lo slurm_pmi.lo step_ctx.lo step_io.lo \ step_launch.lo submit.lo suspend.lo topo_info.lo triggers.lo \ @@ -604,6 +604,7 @@ slurmapi_src = \ partition_info.c \ pmi_server.c \ pmi_server.h \ + powercap_info.c \ reservation_info.c \ signal.c \ slurm_get_statistics.c \ @@ -796,6 +797,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partition_info.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pmi_server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powercap_info.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reconfigure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reservation_info.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ diff --git a/src/api/init_msg.c b/src/api/init_msg.c index 20ef2aeb28fdf0f84883b49615685a9751acc34e..0d0697c8eba386cd607de0e2bf6f2541c92d5cd2 100644 --- a/src/api/init_msg.c +++ b/src/api/init_msg.c @@ -150,6 +150,7 @@ void slurm_init_resv_desc_msg (resv_desc_msg_t * resv_msg) resv_msg->end_time = (time_t) NO_VAL; resv_msg->flags = NO_VAL; resv_msg->start_time = (time_t) NO_VAL; + resv_msg->resv_watts = NO_VAL; } /* diff --git a/src/api/powercap_info.c b/src/api/powercap_info.c new file mode 100644 index 0000000000000000000000000000000000000000..e6f99f648924162313bfa5c2d35e0eab1eedf092 --- /dev/null +++ b/src/api/powercap_info.c @@ -0,0 +1,149 @@ +/*****************************************************************************\ + * powercap_info.c - Definitions for power capping configuration display + ***************************************************************************** + * Copyright (C) 2013 CEA/DAM/DIF + * Written by Matthieu Hautreux <matthieu.hautreux@cea.fr> + * + * This file is part of SLURM, a resource management program. + * For details, see <http://slurm.schedmd.com/>. + * 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. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * 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. +\*****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_SYSLOG_H +# include <sys/syslog.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include "slurm/slurm.h" + +#include "src/common/parse_time.h" +#include "src/common/slurm_protocol_api.h" +#include "src/common/xmalloc.h" +#include "src/common/xstring.h" + +/* + * slurm_load_powercap - issue RPC to get slurm powercapping details + * IN powercap_info_msg_pptr - place to store a pointer to the result + * RET 0 or a slurm error code + * NOTE: free the response using slurm_free_powercap_info_msg + */ +extern int slurm_load_powercap(powercap_info_msg_t **resp) +{ + int rc; + slurm_msg_t req_msg; + slurm_msg_t resp_msg; + + slurm_msg_t_init(&req_msg); + slurm_msg_t_init(&resp_msg); + req_msg.msg_type = REQUEST_POWERCAP_INFO; + req_msg.data = NULL; + + if (slurm_send_recv_controller_msg(&req_msg, &resp_msg) < 0) + return SLURM_ERROR; + + switch (resp_msg.msg_type) { + case RESPONSE_POWERCAP_INFO: + *resp = (powercap_info_msg_t *) resp_msg.data; + break; + case RESPONSE_SLURM_RC: + rc = ((return_code_msg_t *) resp_msg.data)->return_code; + slurm_free_return_code_msg(resp_msg.data); + if (rc) + slurm_seterrno_ret(rc); + *resp = NULL; + break; + default: + slurm_seterrno_ret(SLURM_UNEXPECTED_MSG_ERROR); + break; + } + + return SLURM_PROTOCOL_SUCCESS; +} + +/* + * slurm_print_powercap_info_msg - output information about powercapping + * configuration based upon message as loaded using slurm_load_powercap + * IN out - file to write to + * IN powercap_info_msg_ptr - powercapping information message pointer + * IN one_liner - print as a single line if not zero + */ +extern void slurm_print_powercap_info_msg(FILE * out, powercap_info_msg_t *ptr, + int one_liner) +{ + char tmp_line[512]; + char *out_buf = NULL; + + if (ptr->power_cap == 0) { + /****** Line 1 ******/ + snprintf(tmp_line, sizeof(tmp_line), + "Powercapping disabled by configuration." + " See PowerParameters in `man slurm.conf'"); + xstrcat(out_buf, tmp_line); + xstrcat(out_buf, "\n"); + fprintf(out, "%s", out_buf); + xfree(out_buf); + } else { + /****** Line 1 ******/ + snprintf(tmp_line, sizeof(tmp_line), + "MinWatts=%u CurrentWatts=%u ", + ptr->min_watts, ptr->cur_max_watts); + xstrcat(out_buf, tmp_line); + if (ptr->power_cap == INFINITE) { + snprintf(tmp_line, sizeof(tmp_line), + "PowerCap=INFINITE "); + } else { + snprintf(tmp_line, sizeof(tmp_line), + "PowerCap=%u ", ptr->power_cap); + } + xstrcat(out_buf, tmp_line); + snprintf(tmp_line, sizeof(tmp_line), + "PowerFloor=%u PowerChangeRate=%u", + ptr->power_floor, ptr->power_change); + xstrcat(out_buf, tmp_line); + snprintf(tmp_line, sizeof(tmp_line), + "AdjustedMaxWatts=%u MaxWatts=%u", + ptr->adj_max_watts, ptr->max_watts); + xstrcat(out_buf, tmp_line); + + xstrcat(out_buf, "\n"); + fprintf(out, "%s", out_buf); + xfree(out_buf); + } +} diff --git a/src/api/reservation_info.c b/src/api/reservation_info.c index 7c8ec2dccbc3a4a16932feb70a78ce5313a0e7c3..2f74be6fdd064c1a4062827f06bc9b34620f5edb 100644 --- a/src/api/reservation_info.c +++ b/src/api/reservation_info.c @@ -159,12 +159,16 @@ char *slurm_sprint_reservation_info ( reserve_info_t * resv_ptr, xstrcat(out, "\n "); /****** Line 4 ******/ + if (resv_ptr->resv_watts != (time_t) NO_VAL) { + snprintf(tmp1, 32, "%u", resv_ptr->resv_watts); + } else + snprintf(tmp1, 32, "n/a"); if ((resv_ptr->start_time <= now) && (resv_ptr->end_time >= now)) state = "ACTIVE"; snprintf(tmp_line, sizeof(tmp_line), - "Users=%s Accounts=%s Licenses=%s State=%s BurstBuffer=%s", - resv_ptr->users, resv_ptr->accounts, resv_ptr->licenses, - state, resv_ptr->burst_buffer); + "Users=%s Accounts=%s Licenses=%s State=%s BurstBuffer=%s " + "Watts=%s", resv_ptr->users, resv_ptr->accounts, + resv_ptr->licenses, state, resv_ptr->burst_buffer, tmp1); xstrcat(out, tmp_line); if (one_liner) xstrcat(out, "\n"); diff --git a/src/api/step_ctx.c b/src/api/step_ctx.c index c809049354b71a24c988a3e97aedc22ca0328d1d..e5409ad43acae45e8b1a6ff97801982d80f3ac50 100644 --- a/src/api/step_ctx.c +++ b/src/api/step_ctx.c @@ -253,6 +253,8 @@ slurm_step_ctx_create_timeout (const slurm_step_ctx_params_t *step_params, rc = slurm_job_step_create(step_req, &step_resp); if ((rc < 0) && ((errno == ESLURM_NODES_BUSY) || + (errno == ESLURM_POWER_NOT_AVAIL) || + (errno == ESLURM_POWER_RESERVED) || (errno == ESLURM_PORTS_BUSY) || (errno == ESLURM_INTERCONNECT_BUSY))) { struct pollfd fds; diff --git a/src/api/update_config.c b/src/api/update_config.c index 755de801832d546d63fad99a881e88c1ccd15447..be0f78d7a6248673453884f8816fe075c8c686c9 100644 --- a/src/api/update_config.c +++ b/src/api/update_config.c @@ -176,6 +176,17 @@ slurm_delete_partition ( delete_part_msg_t * part_msg ) return _slurm_update ((void *) part_msg, REQUEST_DELETE_PARTITION); } +/* + * slurm_update_powercap - issue RPC to update powercapping cap + * IN powercap_msg - description of powercapping updates + * RET 0 on success, otherwise return -1 and set errno to indicate the error + */ +int +slurm_update_powercap ( update_powercap_msg_t * powercap_msg ) +{ + return _slurm_update ((void *) powercap_msg, REQUEST_UPDATE_POWERCAP); +} + /* * slurm_create_reservation - create a new reservation, only usable by user root * IN resv_msg - description of reservation diff --git a/src/common/slurm_errno.c b/src/common/slurm_errno.c index ab6e060859c3ce1736c2ea8bc208054d7f354c08..0ae7d20a7b7334e972d6dae3325e6d6e0c9c7be8 100644 --- a/src/common/slurm_errno.c +++ b/src/common/slurm_errno.c @@ -147,6 +147,12 @@ static slurm_errtab_t slurm_errtab[] = { "Requested node configuration is not available" }, { ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE, "Requested partition configuration not available now" }, + { ESLURM_POWER_NOT_AVAIL, + "Required power not available now"}, + { ESLURM_POWER_RESERVED, + "Required power at least partially reserved"}, + { ESLURM_INVALID_POWERCAP, + "Required powercap is not valid, check min/max values"}, { ESLURM_NODES_BUSY, "Requested nodes are busy" }, { ESLURM_INVALID_JOB_ID, diff --git a/src/common/slurm_protocol_api.c b/src/common/slurm_protocol_api.c index 4f09ecc1ff25a6a0de6d1add2739bbdd253f4277..c596c97f74cae0f90210b7fe2a2326a6cd690582 100644 --- a/src/common/slurm_protocol_api.c +++ b/src/common/slurm_protocol_api.c @@ -948,6 +948,22 @@ extern char *slurm_get_power_parameters(void) return power_parameters; } +/* slurm_set_power_parameters + * reset the PowerParameters object + */ +extern void slurm_set_power_parameters(char *power_parameters) +{ + slurm_ctl_conf_t *conf; + + if (slurmdbd_conf) { + } else { + conf = slurm_conf_lock(); + xfree(conf->power_parameters); + conf->power_parameters = xstrdup(power_parameters); + slurm_conf_unlock(); + } +} + /* slurm_get_power_plugin * returns the PowerPlugin from slurmctld_conf object * RET char * - PowerPlugin, MUST be xfreed by caller diff --git a/src/common/slurm_protocol_api.h b/src/common/slurm_protocol_api.h index d52db6ffa55422879a219c8378ca3db6a8fc4051..1876660fc19026bdfea0d6d1e5e82cec655ce7e2 100644 --- a/src/common/slurm_protocol_api.h +++ b/src/common/slurm_protocol_api.h @@ -430,6 +430,11 @@ extern uint16_t slurm_get_use_spec_resources(void); */ extern char *slurm_get_power_parameters(void); +/* slurm_set_power_parameters + * reset the PowerParameters object + */ +extern void slurm_set_power_parameters(char *power_parameters); + /* slurm_get_power_plugin * returns the PowerPlugin from slurmctld_conf object * RET char * - PowerPlugin, MUST be xfreed by caller diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c index 0fcd77c55a8b6f80a08b6a46796201a7552edd0a..35120c127c8045dce390e269b25ded3ff2abab26 100644 --- a/src/common/slurm_protocol_defs.c +++ b/src/common/slurm_protocol_defs.c @@ -1370,6 +1370,10 @@ extern char *job_reason_string(enum job_state_reason inx) return "BurstBufferResources"; case WAIT_BURST_BUFFER_STAGING: return "BurstBufferStageIn"; + case WAIT_POWER_NOT_AVAIL: + return "PowerNotAvail"; + case WAIT_POWER_RESERVED: + return "PowerReserved"; default: snprintf(val, sizeof(val), "%d", inx); return val; @@ -2966,6 +2970,18 @@ extern void slurm_free_burst_buffer_info_msg(burst_buffer_info_msg_t *msg) } } +/* + * slurm_free_powercap_info_msg - free the powercapping information + * response message + * IN msg - pointer to powercapping information response message + * NOTE: buffer is loaded by slurm_load_powercap. + */ +extern void slurm_free_powercap_info_msg(powercap_info_msg_t *msg) +{ + xfree(msg); +} + + extern void slurm_free_file_bcast_msg(file_bcast_msg_t *msg) { if (msg) { @@ -3277,6 +3293,9 @@ extern int slurm_free_msg_data(slurm_msg_type_t type, void *data) case REQUEST_UPDATE_PARTITION: slurm_free_update_part_msg(data); break; + case REQUEST_UPDATE_POWERCAP: + slurm_free_powercap_info_msg(data); + break; case REQUEST_DELETE_PARTITION: slurm_free_delete_part_msg(data); break; @@ -3411,6 +3430,7 @@ extern int slurm_free_msg_data(slurm_msg_type_t type, void *data) case REQUEST_TOPO_INFO: case REQUEST_BURST_BUFFER_INFO: case REQUEST_SICP_INFO: + case REQUEST_POWERCAP_INFO: /* No body to free */ break; case REQUEST_REBOOT_NODES: diff --git a/src/common/slurm_protocol_defs.h b/src/common/slurm_protocol_defs.h index 7ea40289a8a2f462d3f144694f47cbeda71db9e0..d7cf3e52b9d8238cff4e2eb72e110d8ec9d645ee 100644 --- a/src/common/slurm_protocol_defs.h +++ b/src/common/slurm_protocol_defs.h @@ -242,6 +242,8 @@ typedef enum { RESPONSE_BURST_BUFFER_INFO, REQUEST_JOB_USER_INFO, REQUEST_NODE_INFO_SINGLE, /* 2040 */ + REQUEST_POWERCAP_INFO, + RESPONSE_POWERCAP_INFO, REQUEST_CACHE_INFO, RESPONSE_CACHE_INFO, REQUEST_SICP_INFO, @@ -261,6 +263,7 @@ typedef enum { REQUEST_UPDATE_BLOCK, REQUEST_UPDATE_FRONT_END, REQUEST_UPDATE_LAYOUT, + REQUEST_UPDATE_POWERCAP, REQUEST_RESOURCE_ALLOCATION = 4001, RESPONSE_RESOURCE_ALLOCATION, diff --git a/src/common/slurm_protocol_pack.c b/src/common/slurm_protocol_pack.c index 2f05cfc7809c1777ea0c14d188ade9931715a03b..87becbc8287a750f1e42ecc3295cb6d19b90e521 100644 --- a/src/common/slurm_protocol_pack.c +++ b/src/common/slurm_protocol_pack.c @@ -208,6 +208,11 @@ static void _pack_update_partition_msg(update_part_msg_t * msg, Buf buffer, static int _unpack_update_partition_msg(update_part_msg_t ** msg, Buf buffer, uint16_t protocol_version); +static void _pack_update_powercap_msg(update_powercap_msg_t * msg, Buf buffer, + uint16_t protocol_version); +static int _unpack_update_powercap_msg(update_powercap_msg_t ** msg, Buf buffer, + uint16_t protocol_version); + static void _pack_delete_partition_msg(delete_part_msg_t * msg, Buf buffer, uint16_t protocol_version); static int _unpack_delete_partition_msg(delete_part_msg_t ** msg, Buf buffer, @@ -647,6 +652,11 @@ static int _unpack_topo_info_msg(topo_info_response_msg_t **msg, Buf buffer, uint16_t protocol_version); +static void _pack_powercap_info_msg(powercap_info_msg_t *msg, Buf buffer, + uint16_t protocol_version); +static int _unpack_powercap_info_msg(powercap_info_msg_t **msg, + Buf buffer, uint16_t protocol_version); + static void _pack_job_sbcast_cred_msg(job_sbcast_cred_msg_t *msg, Buf buffer, uint16_t protocol_version); static int _unpack_job_sbcast_cred_msg(job_sbcast_cred_msg_t **msg, @@ -971,6 +981,7 @@ pack_msg(slurm_msg_t const *msg, Buf buffer) case REQUEST_TOPO_INFO: case REQUEST_BURST_BUFFER_INFO: case REQUEST_SICP_INFO: + case REQUEST_POWERCAP_INFO: /* Message contains no body/information */ break; case REQUEST_ACCT_GATHER_ENERGY: @@ -1029,6 +1040,11 @@ pack_msg(slurm_msg_t const *msg, Buf buffer) data, buffer, msg->protocol_version); break; + case REQUEST_UPDATE_POWERCAP: + _pack_update_powercap_msg((update_powercap_msg_t *) msg-> + data, buffer, + msg->protocol_version); + break; case REQUEST_DELETE_PARTITION: _pack_delete_partition_msg((delete_part_msg_t *) msg-> data, buffer, @@ -1404,6 +1420,11 @@ pack_msg(slurm_msg_t const *msg, Buf buffer) (topo_info_response_msg_t *)msg->data, buffer, msg->protocol_version); break; + case RESPONSE_POWERCAP_INFO: + _pack_powercap_info_msg( + (powercap_info_msg_t *)msg->data, buffer, + msg->protocol_version); + break; case RESPONSE_JOB_SBCAST_CRED: _pack_job_sbcast_cred_msg( (job_sbcast_cred_msg_t *)msg->data, buffer, @@ -1612,6 +1633,7 @@ unpack_msg(slurm_msg_t * msg, Buf buffer) case REQUEST_TOPO_INFO: case REQUEST_BURST_BUFFER_INFO: case REQUEST_SICP_INFO: + case REQUEST_POWERCAP_INFO: /* Message contains no body/information */ break; case REQUEST_ACCT_GATHER_ENERGY: @@ -1672,6 +1694,11 @@ unpack_msg(slurm_msg_t * msg, Buf buffer) (msg->data), buffer, msg->protocol_version); break; + case REQUEST_UPDATE_POWERCAP: + rc = _unpack_update_powercap_msg((update_powercap_msg_t **) & + (msg->data), buffer, + msg->protocol_version); + break; case REQUEST_DELETE_PARTITION: rc = _unpack_delete_partition_msg((delete_part_msg_t **) & (msg->data), buffer, @@ -2088,6 +2115,11 @@ unpack_msg(slurm_msg_t * msg, Buf buffer) (topo_info_response_msg_t **)&msg->data, buffer, msg->protocol_version); break; + case RESPONSE_POWERCAP_INFO: + rc = _unpack_powercap_info_msg( + (powercap_info_msg_t **)&msg->data, buffer, + msg->protocol_version); + break; case RESPONSE_JOB_SBCAST_CRED: rc = _unpack_job_sbcast_cred_msg( (job_sbcast_cred_msg_t **)&msg->data, buffer, @@ -3968,6 +4000,22 @@ unpack_error: return SLURM_ERROR; } +static void +_pack_update_powercap_msg(update_powercap_msg_t * msg, Buf buffer, + uint16_t protocol_version) +{ + _pack_powercap_info_msg((powercap_info_msg_t *) msg, + buffer, protocol_version); +} + +static int +_unpack_update_powercap_msg(update_powercap_msg_t ** msg, Buf buffer, + uint16_t protocol_version) +{ + return _unpack_powercap_info_msg((powercap_info_msg_t **) msg, + buffer, protocol_version); +} + static void _pack_update_resv_msg(resv_desc_msg_t * msg, Buf buffer, uint16_t protocol_version) @@ -4004,6 +4052,7 @@ _pack_update_resv_msg(resv_desc_msg_t * msg, Buf buffer, packstr(msg->licenses, buffer); packstr(msg->partition, buffer); + pack32(msg->resv_watts, buffer); packstr(msg->users, buffer); packstr(msg->accounts, buffer); packstr(msg->burst_buffer, buffer); @@ -4089,6 +4138,7 @@ _unpack_update_resv_msg(resv_desc_msg_t ** msg, Buf buffer, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&tmp_ptr->partition, &uint32_tmp, buffer); + safe_unpack32(&tmp_ptr->resv_watts, buffer); safe_unpackstr_xmalloc(&tmp_ptr->users, &uint32_tmp, buffer); @@ -4128,6 +4178,7 @@ _unpack_update_resv_msg(resv_desc_msg_t ** msg, Buf buffer, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&tmp_ptr->partition, &uint32_tmp, buffer); + tmp_ptr->resv_watts = NO_VAL; safe_unpackstr_xmalloc(&tmp_ptr->users, &uint32_tmp, buffer); @@ -5059,6 +5110,7 @@ _unpack_reserve_info_members(reserve_info_t * resv, Buf buffer, safe_unpack32(&resv->node_cnt, buffer); safe_unpackstr_xmalloc(&resv->node_list, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&resv->partition, &uint32_tmp, buffer); + safe_unpack32(&resv->resv_watts, buffer); safe_unpack_time(&resv->start_time, buffer); safe_unpackstr_xmalloc(&resv->tres_str, &uint32_tmp, buffer); @@ -7252,10 +7304,10 @@ _unpack_slurm_ctl_conf_msg(slurm_ctl_conf_info_msg_t **build_buffer_ptr, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&build_ptr->plugstack, &uint32_tmp, buffer); + safe_unpack16(&build_ptr->preempt_mode, buffer); safe_unpackstr_xmalloc(&build_ptr->preempt_type, &uint32_tmp, buffer); - safe_unpack32(&build_ptr->priority_decay_hl, buffer); safe_unpack32(&build_ptr->priority_calc_period, buffer); safe_unpack16(&build_ptr->priority_favor_small, buffer); @@ -12722,6 +12774,40 @@ unpack_error: return SLURM_ERROR; } +static void _pack_powercap_info_msg(powercap_info_msg_t *msg, Buf buffer, + uint16_t protocol_version) +{ + pack32(msg->power_cap, buffer); + pack32(msg->power_floor, buffer); + pack32(msg->power_change, buffer); + pack32(msg->min_watts, buffer); + pack32(msg->cur_max_watts, buffer); + pack32(msg->adj_max_watts, buffer); + pack32(msg->max_watts, buffer); +} + +static int _unpack_powercap_info_msg(powercap_info_msg_t **msg, Buf buffer, + uint16_t protocol_version) +{ + powercap_info_msg_t *msg_ptr = xmalloc(sizeof(powercap_info_msg_t)); + + *msg = msg_ptr; + safe_unpack32(&msg_ptr->power_cap, buffer); + safe_unpack32(&msg_ptr->power_floor, buffer); + safe_unpack32(&msg_ptr->power_change, buffer); + safe_unpack32(&msg_ptr->min_watts, buffer); + safe_unpack32(&msg_ptr->cur_max_watts, buffer); + safe_unpack32(&msg_ptr->adj_max_watts, buffer); + safe_unpack32(&msg_ptr->max_watts, buffer); + + return SLURM_SUCCESS; + +unpack_error: + slurm_free_powercap_info_msg(msg_ptr); + *msg = NULL; + return SLURM_ERROR; +} + static void _pack_spank_env_request_msg(spank_env_request_msg_t * msg, Buf buffer, uint16_t protocol_version) { diff --git a/src/layouts/Makefile.am b/src/layouts/Makefile.am index 54f8ba015f63a6bef632339d13bce850f687ee65..d9d8a83baef57a91fb64f75e20c053f853d4e367 100644 --- a/src/layouts/Makefile.am +++ b/src/layouts/Makefile.am @@ -1,4 +1,4 @@ # Makefile for layouts plugins -SUBDIRS = unit +SUBDIRS = unit power #basic racking energy power topology diff --git a/src/layouts/Makefile.in b/src/layouts/Makefile.in index 8bd8d63e0a4b22e7d2558d92609db9cc03a8badd..87e043ddebecf52894a75678bbcf2fda9b83a446 100644 --- a/src/layouts/Makefile.in +++ b/src/layouts/Makefile.in @@ -459,7 +459,7 @@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = unit +SUBDIRS = unit power all: all-recursive .SUFFIXES: diff --git a/src/layouts/power/Makefile.am b/src/layouts/power/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..58bff846fb042c9f66adc06cf828aeaf6176c9d3 --- /dev/null +++ b/src/layouts/power/Makefile.am @@ -0,0 +1,10 @@ +AUTOMAKE_OPTIONS = foreign + +PLUGIN_FLAGS = -module -avoid-version --export-dynamic + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src/common + +pkglib_LTLIBRARIES = layouts_power_default.la + +layouts_power_default_la_SOURCES = default.c +layouts_power_default_la_LDFLAGS = $(SO_LDFLAGS) $(PLUGIN_FLAGS) diff --git a/src/layouts/power/Makefile.in b/src/layouts/power/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..44338a44fe509cf8217e2bb001240c6b42137d1f --- /dev/null +++ b/src/layouts/power/Makefile.in @@ -0,0 +1,807 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/layouts/power +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/auxdir/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/auxdir/ax_lib_hdf5.m4 \ + $(top_srcdir)/auxdir/ax_pthread.m4 \ + $(top_srcdir)/auxdir/libtool.m4 \ + $(top_srcdir)/auxdir/ltoptions.m4 \ + $(top_srcdir)/auxdir/ltsugar.m4 \ + $(top_srcdir)/auxdir/ltversion.m4 \ + $(top_srcdir)/auxdir/lt~obsolete.m4 \ + $(top_srcdir)/auxdir/slurm.m4 \ + $(top_srcdir)/auxdir/x_ac__system_configuration.m4 \ + $(top_srcdir)/auxdir/x_ac_affinity.m4 \ + $(top_srcdir)/auxdir/x_ac_aix.m4 \ + $(top_srcdir)/auxdir/x_ac_blcr.m4 \ + $(top_srcdir)/auxdir/x_ac_bluegene.m4 \ + $(top_srcdir)/auxdir/x_ac_cflags.m4 \ + $(top_srcdir)/auxdir/x_ac_cray.m4 \ + $(top_srcdir)/auxdir/x_ac_curl.m4 \ + $(top_srcdir)/auxdir/x_ac_databases.m4 \ + $(top_srcdir)/auxdir/x_ac_debug.m4 \ + $(top_srcdir)/auxdir/x_ac_dlfcn.m4 \ + $(top_srcdir)/auxdir/x_ac_env.m4 \ + $(top_srcdir)/auxdir/x_ac_freeipmi.m4 \ + $(top_srcdir)/auxdir/x_ac_gpl_licensed.m4 \ + $(top_srcdir)/auxdir/x_ac_hwloc.m4 \ + $(top_srcdir)/auxdir/x_ac_iso.m4 \ + $(top_srcdir)/auxdir/x_ac_json.m4 \ + $(top_srcdir)/auxdir/x_ac_lua.m4 \ + $(top_srcdir)/auxdir/x_ac_man2html.m4 \ + $(top_srcdir)/auxdir/x_ac_munge.m4 \ + $(top_srcdir)/auxdir/x_ac_ncurses.m4 \ + $(top_srcdir)/auxdir/x_ac_netloc.m4 \ + $(top_srcdir)/auxdir/x_ac_nrt.m4 \ + $(top_srcdir)/auxdir/x_ac_ofed.m4 \ + $(top_srcdir)/auxdir/x_ac_pam.m4 \ + $(top_srcdir)/auxdir/x_ac_printf_null.m4 \ + $(top_srcdir)/auxdir/x_ac_ptrace.m4 \ + $(top_srcdir)/auxdir/x_ac_readline.m4 \ + $(top_srcdir)/auxdir/x_ac_rrdtool.m4 \ + $(top_srcdir)/auxdir/x_ac_setpgrp.m4 \ + $(top_srcdir)/auxdir/x_ac_setproctitle.m4 \ + $(top_srcdir)/auxdir/x_ac_sgi_job.m4 \ + $(top_srcdir)/auxdir/x_ac_slurm_ssl.m4 \ + $(top_srcdir)/auxdir/x_ac_sun_const.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h $(top_builddir)/slurm/slurm.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +layouts_power_default_la_LIBADD = +am_layouts_power_default_la_OBJECTS = default.lo +layouts_power_default_la_OBJECTS = \ + $(am_layouts_power_default_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +layouts_power_default_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(layouts_power_default_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/slurm +depcomp = $(SHELL) $(top_srcdir)/auxdir/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(layouts_power_default_la_SOURCES) +DIST_SOURCES = $(layouts_power_default_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTHD_CFLAGS = @AUTHD_CFLAGS@ +AUTHD_LIBS = @AUTHD_LIBS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGL_LOADED = @BGL_LOADED@ +BGQ_LOADED = @BGQ_LOADED@ +BG_INCLUDES = @BG_INCLUDES@ +BG_LDFLAGS = @BG_LDFLAGS@ +BG_L_P_LOADED = @BG_L_P_LOADED@ +BLCR_CPPFLAGS = @BLCR_CPPFLAGS@ +BLCR_HOME = @BLCR_HOME@ +BLCR_LDFLAGS = @BLCR_LDFLAGS@ +BLCR_LIBS = @BLCR_LIBS@ +BLUEGENE_LOADED = @BLUEGENE_LOADED@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CMD_LDFLAGS = @CMD_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRAY_JOB_CPPFLAGS = @CRAY_JOB_CPPFLAGS@ +CRAY_JOB_LDFLAGS = @CRAY_JOB_LDFLAGS@ +CRAY_SELECT_CPPFLAGS = @CRAY_SELECT_CPPFLAGS@ +CRAY_SELECT_LDFLAGS = @CRAY_SELECT_LDFLAGS@ +CRAY_SWITCH_CPPFLAGS = @CRAY_SWITCH_CPPFLAGS@ +CRAY_SWITCH_LDFLAGS = @CRAY_SWITCH_LDFLAGS@ +CRAY_TASK_CPPFLAGS = @CRAY_TASK_CPPFLAGS@ +CRAY_TASK_LDFLAGS = @CRAY_TASK_LDFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DL_LIBS = @DL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FREEIPMI_CPPFLAGS = @FREEIPMI_CPPFLAGS@ +FREEIPMI_LDFLAGS = @FREEIPMI_LDFLAGS@ +FREEIPMI_LIBS = @FREEIPMI_LIBS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GREP = @GREP@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +H5CC = @H5CC@ +H5FC = @H5FC@ +HAVEMYSQLCONFIG = @HAVEMYSQLCONFIG@ +HAVE_AIX = @HAVE_AIX@ +HAVE_MAN2HTML = @HAVE_MAN2HTML@ +HAVE_NRT = @HAVE_NRT@ +HAVE_OPENSSL = @HAVE_OPENSSL@ +HAVE_SOME_CURSES = @HAVE_SOME_CURSES@ +HDF5_CC = @HDF5_CC@ +HDF5_CFLAGS = @HDF5_CFLAGS@ +HDF5_CPPFLAGS = @HDF5_CPPFLAGS@ +HDF5_FC = @HDF5_FC@ +HDF5_FFLAGS = @HDF5_FFLAGS@ +HDF5_FLIBS = @HDF5_FLIBS@ +HDF5_LDFLAGS = @HDF5_LDFLAGS@ +HDF5_LIBS = @HDF5_LIBS@ +HDF5_VERSION = @HDF5_VERSION@ +HWLOC_CPPFLAGS = @HWLOC_CPPFLAGS@ +HWLOC_LDFLAGS = @HWLOC_LDFLAGS@ +HWLOC_LIBS = @HWLOC_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JSON_CPPFLAGS = @JSON_CPPFLAGS@ +JSON_LDFLAGS = @JSON_LDFLAGS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_LDFLAGS = @LIB_LDFLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MUNGE_CPPFLAGS = @MUNGE_CPPFLAGS@ +MUNGE_DIR = @MUNGE_DIR@ +MUNGE_LDFLAGS = @MUNGE_LDFLAGS@ +MUNGE_LIBS = @MUNGE_LIBS@ +MYSQL_CFLAGS = @MYSQL_CFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NCURSES = @NCURSES@ +NETLOC_CPPFLAGS = @NETLOC_CPPFLAGS@ +NETLOC_LDFLAGS = @NETLOC_LDFLAGS@ +NETLOC_LIBS = @NETLOC_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NRT_CPPFLAGS = @NRT_CPPFLAGS@ +NUMA_LIBS = @NUMA_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OFED_CPPFLAGS = @OFED_CPPFLAGS@ +OFED_LDFLAGS = @OFED_LDFLAGS@ +OFED_LIBS = @OFED_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PAM_DIR = @PAM_DIR@ +PAM_LIBS = @PAM_LIBS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROCTRACKDIR = @PROCTRACKDIR@ +PROJECT = @PROJECT@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +REAL_BGQ_LOADED = @REAL_BGQ_LOADED@ +REAL_BG_L_P_LOADED = @REAL_BG_L_P_LOADED@ +RELEASE = @RELEASE@ +RRDTOOL_CPPFLAGS = @RRDTOOL_CPPFLAGS@ +RRDTOOL_LDFLAGS = @RRDTOOL_LDFLAGS@ +RRDTOOL_LIBS = @RRDTOOL_LIBS@ +RUNJOB_LDFLAGS = @RUNJOB_LDFLAGS@ +SED = @SED@ +SEMAPHORE_LIBS = @SEMAPHORE_LIBS@ +SEMAPHORE_SOURCES = @SEMAPHORE_SOURCES@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SLEEP_CMD = @SLEEP_CMD@ +SLURMCTLD_PORT = @SLURMCTLD_PORT@ +SLURMCTLD_PORT_COUNT = @SLURMCTLD_PORT_COUNT@ +SLURMDBD_PORT = @SLURMDBD_PORT@ +SLURMD_PORT = @SLURMD_PORT@ +SLURM_API_AGE = @SLURM_API_AGE@ +SLURM_API_CURRENT = @SLURM_API_CURRENT@ +SLURM_API_MAJOR = @SLURM_API_MAJOR@ +SLURM_API_REVISION = @SLURM_API_REVISION@ +SLURM_API_VERSION = @SLURM_API_VERSION@ +SLURM_MAJOR = @SLURM_MAJOR@ +SLURM_MICRO = @SLURM_MICRO@ +SLURM_MINOR = @SLURM_MINOR@ +SLURM_PREFIX = @SLURM_PREFIX@ +SLURM_VERSION_NUMBER = @SLURM_VERSION_NUMBER@ +SLURM_VERSION_STRING = @SLURM_VERSION_STRING@ +SO_LDFLAGS = @SO_LDFLAGS@ +SSL_CPPFLAGS = @SSL_CPPFLAGS@ +SSL_LDFLAGS = @SSL_LDFLAGS@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SUCMD = @SUCMD@ +UTIL_LIBS = @UTIL_LIBS@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_have_man2html = @ac_have_man2html@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lua_CFLAGS = @lua_CFLAGS@ +lua_LIBS = @lua_LIBS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +PLUGIN_FLAGS = -module -avoid-version --export-dynamic +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src/common +pkglib_LTLIBRARIES = layouts_power_default.la +layouts_power_default_la_SOURCES = default.c +layouts_power_default_la_LDFLAGS = $(SO_LDFLAGS) $(PLUGIN_FLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/layouts/power/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/layouts/power/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +layouts_power_default.la: $(layouts_power_default_la_OBJECTS) $(layouts_power_default_la_DEPENDENCIES) $(EXTRA_layouts_power_default_la_DEPENDENCIES) + $(AM_V_CCLD)$(layouts_power_default_la_LINK) -rpath $(pkglibdir) $(layouts_power_default_la_OBJECTS) $(layouts_power_default_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/default.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pkglibLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-pkglibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/layouts/power/default.c b/src/layouts/power/default.c new file mode 100644 index 0000000000000000000000000000000000000000..0a80eb4ccccfb24a785cb8367c0d63a9b4297e5c --- /dev/null +++ b/src/layouts/power/default.c @@ -0,0 +1,119 @@ +/** TODO: copyright notice */ + +#include "slurm/slurm.h" + +#include "src/common/layouts_mgr.h" +#include "src/common/entity.h" +#include "src/common/log.h" + +const char plugin_name[] = "Power layouts plugin"; +const char plugin_type[] = "layouts/power"; +const uint32_t plugin_version = SLURM_VERSION_NUMBER; + +/* specific options for power tests layout */ +s_p_options_t entity_options[] = { + /* base keys */ + {"CurrentPower", S_P_UINT32}, + {"IdleWatts", S_P_UINT32}, + {"MaxWatts", S_P_UINT32}, + {"DownWatts",S_P_UINT32}, + {"PowerSaveWatts",S_P_UINT32}, + /* parents aggregated keys */ + {"CurrentSumPower", S_P_UINT32}, + {"IdleSumWatts", S_P_UINT32}, + {"MaxSumWatts", S_P_UINT32}, + {NULL} +}; +s_p_options_t options[] = { + {"Entity", S_P_EXPLINE, NULL, NULL, entity_options}, + {NULL} +}; + +const layouts_keyspec_t keyspec[] = { + /* base keys */ + {"CurrentPower", L_T_UINT32}, + {"IdleWatts", L_T_UINT32}, + {"MaxWatts", L_T_UINT32}, + {"DownWatts",L_T_UINT32}, + {"PowerSaveWatts",L_T_UINT32}, + {"NumFreqChoices",L_T_UINT32}, + /* parents aggregated keys */ + {"CurrentSumPower", L_T_UINT32, + KEYSPEC_UPDATE_CHILDREN_SUM, "CurrentPower"}, + {"IdleSumWatts", L_T_UINT32, + KEYSPEC_UPDATE_CHILDREN_SUM, "IdleWatts"}, + {"MaxSumWatts", L_T_UINT32, + KEYSPEC_UPDATE_CHILDREN_SUM, "MaxWatts"}, + {NULL} + +}; + +/* types allowed in the entity's "type" field */ +const char* etypes[] = { + "Center", + "Node", + NULL +}; + +const layouts_plugin_spec_t plugin_spec = { + options, + keyspec, + LAYOUT_STRUCT_TREE, + etypes, + true, /* if this evalued to true, keys inside plugin_keyspec present in + * plugin_options having corresponding types, are automatically + * handled by the layouts manager. + */ + true /* if this evalued to true, keys updates trigger an automatic + * update of their entities neighborhoods based on their + * KEYSPEC_UPDATE_* set flags + */ +}; + +/* manager is lock when this function is called */ +/* disable this callback by setting it to NULL, warn: not every callback can + * be desactivated this way */ +int layouts_p_conf_done( + xhash_t* entities, layout_t* layout, s_p_hashtbl_t* tbl) +{ + return 1; +} + + +/* disable this callback by setting it to NULL, warn: not every callback can + * be desactivated this way */ +void layouts_p_entity_parsing( + entity_t* e, s_p_hashtbl_t* etbl, layout_t* layout) +{ +} + +/* manager is lock then this function is called */ +/* disable this callback by setting it to NULL, warn: not every callback can + * be desactivated this way */ +int layouts_p_update_done(layout_t* layout, entity_t** e_array, int e_cnt) +{ + int i; + debug3("layouts/power: receiving update callback for %d entities", + e_cnt); + for (i = 0; i < e_cnt; i++) { + if (e_array[i] == NULL) { + debug3("layouts/power: skipping update of nullified" + "entity[%d]", i); + } else { + debug3("layouts/power: updating entity[%d]=%s", + i, e_array[i]->name); + } + } + return 1; +} + +int init(void) +{ + return SLURM_SUCCESS; +} + +int fini(void) +{ + return SLURM_SUCCESS; +} + diff --git a/src/plugins/sched/backfill/backfill.c b/src/plugins/sched/backfill/backfill.c index 3f9c5e10c3f27fafac7b23e335e1d9170711a5ed..432fb062b779daeb642d8907816868161b5d5620 100644 --- a/src/plugins/sched/backfill/backfill.c +++ b/src/plugins/sched/backfill/backfill.c @@ -792,13 +792,17 @@ static int _attempt_backfill(void) filter_root = true; job_queue = build_job_queue(true, true); - if (list_count(job_queue) == 0) { + job_test_count = list_count(job_queue); + if (job_test_count == 0) { if (debug_flags & DEBUG_FLAG_BACKFILL) info("backfill: no jobs to backfill"); else debug("backfill: no jobs to backfill"); list_destroy(job_queue); return 0; + } else { + debug("backfill: %u jobs to backfill", job_test_count); + job_test_count = 0; } if (backfill_continue) @@ -1294,7 +1298,9 @@ next_task: } if ((rc == ESLURM_ACCOUNTING_POLICY) || - (rc == ESLURM_RESERVATION_BUSY)) { + (rc == ESLURM_RESERVATION_BUSY) || + (rc == ESLURM_POWER_NOT_AVAIL) || + (rc == ESLURM_POWER_RESERVED)) { /* Unknown future start time, just skip job */ if (orig_start_time != 0) { /* Can start in different partition */ diff --git a/src/scontrol/Makefile.am b/src/scontrol/Makefile.am index aec33501ef6c5239c187acbf0d10dba6119ce05c..8625207580e917f736ceb2e6ec6cf38fe8150e36 100644 --- a/src/scontrol/Makefile.am +++ b/src/scontrol/Makefile.am @@ -23,7 +23,8 @@ scontrol_SOURCES = \ update_layout.c \ update_node.c \ update_part.c \ - update_step.c + update_step.c \ + update_powercap.c convenience_libs = $(top_builddir)/src/api/libslurm.o $(DL_LIBS) -lm diff --git a/src/scontrol/Makefile.in b/src/scontrol/Makefile.in index 5d9ccfe9b2981ff9eadd20b2b306d5caa48b089c..a3b610efafe57ceef2e62fcdebd2b466d6197216 100644 --- a/src/scontrol/Makefile.in +++ b/src/scontrol/Makefile.in @@ -143,7 +143,8 @@ am_scontrol_OBJECTS = create_res.$(OBJEXT) info_block.$(OBJEXT) \ info_node.$(OBJEXT) info_part.$(OBJEXT) info_res.$(OBJEXT) \ scontrol.$(OBJEXT) update_job.$(OBJEXT) \ update_layout.$(OBJEXT) update_node.$(OBJEXT) \ - update_part.$(OBJEXT) update_step.$(OBJEXT) + update_part.$(OBJEXT) update_step.$(OBJEXT) \ + update_powercap.$(OBJEXT) scontrol_OBJECTS = $(am_scontrol_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(top_builddir)/src/api/libslurm.o \ @@ -482,7 +483,8 @@ scontrol_SOURCES = \ update_layout.c \ update_node.c \ update_part.c \ - update_step.c + update_step.c \ + update_powercap.c convenience_libs = $(top_builddir)/src/api/libslurm.o $(DL_LIBS) -lm scontrol_LDADD = \ @@ -599,6 +601,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_layout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_node.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_part.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_powercap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_step.Po@am__quote@ .c.o: diff --git a/src/scontrol/create_res.c b/src/scontrol/create_res.c index 5e21062b4022d97fdba2df4cc78b4231a60f9fee..cb6afab280a5d1c6c8bafedf5db3d6e808ce8366 100644 --- a/src/scontrol/create_res.c +++ b/src/scontrol/create_res.c @@ -284,6 +284,11 @@ scontrol_parse_res_options(int argc, char *argv[], const char *msg, } else { resv_msg_ptr->users = val; } + } else if (strncasecmp(tag, "Watts", MAX(taglen, 1)) == 0) { + if (parse_uint32(val, &(resv_msg_ptr->resv_watts))) { + error("Invalid Watts value: %s", val); + return -1; + } } else if (strncasecmp(tag, "res", 3) == 0) { continue; } else { @@ -429,11 +434,13 @@ scontrol_create_res(int argc, char *argv[]) resv_msg.burst_buffer[0] == '\0') && (resv_msg.node_cnt == NULL || resv_msg.node_cnt[0] == 0) && (resv_msg.node_list == NULL || resv_msg.node_list[0] == '\0') && - (resv_msg.licenses == NULL || resv_msg.licenses[0] == '\0')) { + (resv_msg.licenses == NULL || resv_msg.licenses[0] == '\0') && + (resv_msg.resv_watts == NO_VAL)) { if (resv_msg.partition == NULL) { exit_code = 1; - error("CoreCnt, Nodes, NodeCnt, BurstBuffer or Licenses" - " must be specified. No reservation created."); + error("CoreCnt, Nodes, NodeCnt, BurstBuffer, Licenses" + "or Watts must be specified. No reservation " + "created."); goto SCONTROL_CREATE_RES_CLEANUP; } if (resv_msg.flags == (uint16_t) NO_VAL) @@ -449,7 +456,17 @@ scontrol_create_res(int argc, char *argv[]) "No reservation created."); goto SCONTROL_CREATE_RES_CLEANUP; } - + if (resv_msg.resv_watts != NO_VAL && + (!(resv_msg.flags & RESERVE_FLAG_ANY_NODES) || + (resv_msg.core_cnt != 0) || + (resv_msg.node_cnt != NULL && resv_msg.node_cnt[0] != 0) || + (resv_msg.node_list != NULL && resv_msg.node_list[0] != '\0') || + (resv_msg.licenses != NULL && resv_msg.licenses[0] != '\0'))) { + exit_code = 1; + error("A power reservation must be empty and set the " + "LICENSE_ONLY flag. No reservation created."); + goto SCONTROL_CREATE_RES_CLEANUP; + } new_res_name = slurm_create_reservation(&resv_msg); if (!new_res_name) { exit_code = 1; diff --git a/src/scontrol/info_node.c b/src/scontrol/info_node.c index c503b58351d35c763f3ed0f96946d52fbeff5f24..3f4f025b3723a3ecce927c00b3724b8b7804a4ab 100644 --- a/src/scontrol/info_node.c +++ b/src/scontrol/info_node.c @@ -242,6 +242,29 @@ extern void scontrol_print_topo (char *node_list) } } +/* + * scontrol_print_powercap - print the powercapping related information + * above the specified node(s) + * IN node_list - NULL to print the overall powercapping details + */ +extern void scontrol_print_powercap (char *node_list) +{ + static powercap_info_msg_t *powercap_info_msg = NULL; + + if ((powercap_info_msg == NULL) && + slurm_load_powercap(&powercap_info_msg)) { + slurm_perror ("slurm_load_powercap error"); + return; + } + + /* TODO: the case of a particular node list is not yet treated here */ + if ((node_list == NULL) || (node_list[0] == '\0')) { + slurm_print_powercap_info_msg(stdout, powercap_info_msg, + one_liner); + return; + } +} + /* * Load current front_end table information into *node_buffer_pptr */ diff --git a/src/scontrol/scontrol.c b/src/scontrol/scontrol.c index 49e0ac4c114045e5357dd80832c45c29b47a96af..d5bcbfb91182dec6e25dbb14017cc47738d92e40 100644 --- a/src/scontrol/scontrol.c +++ b/src/scontrol/scontrol.c @@ -1552,9 +1552,11 @@ _show_it (int argc, char *argv[]) scontrol_print_licenses(val); } else if (strncasecmp (tag, "nodes", MAX(tag_len, 1)) == 0) { scontrol_print_node_list (val); - } else if (strncasecmp (tag, "partitions", MAX(tag_len, 1)) == 0 || - strncasecmp (tag, "partitionname", MAX(tag_len, 1)) == 0) { + } else if (strncasecmp (tag, "partitions", MAX(tag_len, 2)) == 0 || + strncasecmp (tag, "partitionname", MAX(tag_len, 2)) == 0) { scontrol_print_part (val); + } else if (strncasecmp (tag, "powercapping", MAX(tag_len, 2)) == 0) { + scontrol_print_powercap (val); } else if (strncasecmp (tag, "reservations", MAX(tag_len, 1)) == 0 || strncasecmp (tag, "reservationname", MAX(tag_len, 1)) == 0) { scontrol_print_res (val); @@ -1592,6 +1594,7 @@ _update_it (int argc, char *argv[]) int block_tag = 0, sub_tag = 0, res_tag = 0; int debug_tag = 0, step_tag = 0, front_end_tag = 0; int layout_tag = 0; + int powercap_tag = 0; int jerror_code = SLURM_SUCCESS; /* First identify the entity to update */ @@ -1633,6 +1636,8 @@ _update_it (int argc, char *argv[]) debug_tag = 1; } else if (!strncasecmp(tag, "Layouts", MAX(tag_len, 5))) { layout_tag = 1; + } else if (!strncasecmp(tag, "PowerCap", MAX(tag_len, 3))) { + powercap_tag = 1; } } /* The order of tests matters here. An update job request can include @@ -1662,6 +1667,8 @@ _update_it (int argc, char *argv[]) error_code = _update_slurmctld_debug(val); else if (layout_tag) error_code = scontrol_update_layout(argc, argv); + else if (powercap_tag) + error_code = scontrol_update_powercap (argc, argv); else { exit_code = 1; fprintf(stderr, "No valid entity in update command\n"); @@ -1671,7 +1678,8 @@ _update_it (int argc, char *argv[]) "(i.e. bgl000[0-3]),"); } fprintf(stderr, "\"PartitionName\", \"Reservation\", " - "\"JobId\", \"SlurmctldDebug\" or \"Layouts\"\n"); + "\"JobId\", \"SlurmctldDebug\" , \"PowerCap\"" + "or \"Layouts\"\n"); } if (error_code) { diff --git a/src/scontrol/scontrol.h b/src/scontrol/scontrol.h index c042f0e43da4ebbdbb30c71df3b9376b8b50e3a5..040a2c7a945dbc052464ac667eac54bf4198f0f5 100644 --- a/src/scontrol/scontrol.h +++ b/src/scontrol/scontrol.h @@ -159,6 +159,7 @@ extern void scontrol_print_res (char *reservation_name); extern void scontrol_print_step (char *job_step_id_str); extern void scontrol_print_topo (char *node_list); extern void scontrol_print_layout (int argc, char *argv[]); +extern void scontrol_print_powercap (char *node_list); extern void scontrol_requeue(int argc, char **argv); extern void scontrol_requeue_hold(int argc, char **argv); extern void scontrol_suspend(char *op, char *job_id_str); @@ -169,5 +170,6 @@ extern int scontrol_update_node (int argc, char *argv[]); extern int scontrol_update_part (int argc, char *argv[]); extern int scontrol_update_res (int argc, char *argv[]); extern int scontrol_update_step (int argc, char *argv[]); +extern int scontrol_update_powercap (int argc, char *argv[]); #endif diff --git a/src/scontrol/update_layout.c b/src/scontrol/update_layout.c index af90e1e767d7edc7f81ff819ee690d2d1d4f3d30..9e05fbc7f98de2710bc8550806fb7c99ab3e7325 100644 --- a/src/scontrol/update_layout.c +++ b/src/scontrol/update_layout.c @@ -46,7 +46,7 @@ extern int scontrol_update_layout (int argc, char *argv[]) { - int rc; + int rc = 0; int i = 0, tag_len = 0; char *tag = NULL, *val = NULL; update_layout_msg_t msg; @@ -56,7 +56,6 @@ scontrol_update_layout (int argc, char *argv[]) memset(&msg, 0, sizeof(update_layout_msg_t)); while (i < argc) { tag = argv[i]; - tag_len = strlen(tag); val = strchr(argv[i], '='); if (val) { tag_len = val - argv[i]; diff --git a/src/scontrol/update_powercap.c b/src/scontrol/update_powercap.c new file mode 100644 index 0000000000000000000000000000000000000000..7b04a47e9a51fa39aaedf00d00d775c0cc875ab9 --- /dev/null +++ b/src/scontrol/update_powercap.c @@ -0,0 +1,111 @@ +/*****************************************************************************\ + * update_powercap.c - powercapping update function for scontrol. + ***************************************************************************** + * Copyright (C) 2013 CEA/DAM/DIF + * Written by Matthieu Hautreux <matthieu.hautreux@cea.fr> + * + * This file is part of SLURM, a resource management program. + * For details, see <http://slurm.schedmd.com/>. + * 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. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * 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. +\*****************************************************************************/ + +#include "src/common/proc_args.h" +#include "src/scontrol/scontrol.h" + +static uint32_t _parse_watts(char * watts_str) +{ + uint32_t watts_num = 0; + char *end_ptr = NULL; + + if (!strcasecmp(watts_str, "n/a") || !strcasecmp(watts_str, "none")) + return watts_num; + if (!strcasecmp(watts_str, "INFINITE")) + return INFINITE; + watts_num = strtol(watts_str, &end_ptr, 10); + if ((end_ptr[0] == 'k') || (end_ptr[0] == 'K')) + watts_num *= 1000; + else if ((end_ptr[0] == 'm') || (end_ptr[0] == 'M')) + watts_num *= 1000000; + else if (end_ptr[0] != '\0') + watts_num = NO_VAL; + return watts_num; +} + +/* + * scontrol_update_powercap - update the slurm powercapping configuration per the + * supplied arguments + * IN argc - count of arguments + * IN argv - list of arguments + * RET 0 if no slurm error, errno otherwise. parsing error prints + * error message and returns 0 + */ +extern int +scontrol_update_powercap (int argc, char *argv[]) +{ + update_powercap_msg_t powercap_msg; + int i; + char *tag, *val; + int taglen; + + memset(&powercap_msg, 0, sizeof(update_powercap_msg_t)); + powercap_msg.power_cap = NO_VAL; + powercap_msg.min_watts = NO_VAL; + powercap_msg.cur_max_watts = NO_VAL; + powercap_msg.adj_max_watts = NO_VAL; + powercap_msg.max_watts = NO_VAL; + + for (i = 0; i < argc; i++) { + tag = argv[i]; + val = strchr(argv[i], '='); + if (val) { + taglen = val - argv[i]; + val++; + } else { + exit_code = 1; + error("Invalid input: %s Request aborted", argv[i]); + return -1; + } + + if (strncasecmp(tag, "PowerCap", MAX(taglen, 8)) == 0) { + powercap_msg.power_cap = _parse_watts(val); + break; + } + } + + if (powercap_msg.power_cap == NO_VAL) { + exit_code = 1; + error("Invalid PowerCap value."); + return 0; + } + + if (slurm_update_powercap(&powercap_msg)) { + exit_code = 1; + return slurm_get_errno (); + } else + return 0; +} diff --git a/src/slurmctld/Makefile.am b/src/slurmctld/Makefile.am index f3882d27dd3a62f7fcc6ac136d3183c03f80e4a8..aad26e0d4f0a199230c49758f5c6f1cd5b5fa7d2 100644 --- a/src/slurmctld/Makefile.am +++ b/src/slurmctld/Makefile.am @@ -45,6 +45,8 @@ slurmctld_SOURCES = \ port_mgr.c \ port_mgr.h \ power_save.c \ + powercapping.c \ + powercapping.h \ preempt.c \ preempt.h \ proc_req.c \ diff --git a/src/slurmctld/Makefile.in b/src/slurmctld/Makefile.in index 968d10162ddb4361a38488616a9087ce201a19e9..04c3e787142f0683daf925cab4b4e8a249ef308c 100644 --- a/src/slurmctld/Makefile.in +++ b/src/slurmctld/Makefile.in @@ -146,8 +146,8 @@ am_slurmctld_OBJECTS = acct_policy.$(OBJEXT) agent.$(OBJEXT) \ node_mgr.$(OBJEXT) node_scheduler.$(OBJEXT) \ partition_mgr.$(OBJEXT) ping_nodes.$(OBJEXT) \ slurmctld_plugstack.$(OBJEXT) port_mgr.$(OBJEXT) \ - power_save.$(OBJEXT) preempt.$(OBJEXT) proc_req.$(OBJEXT) \ - read_config.$(OBJEXT) reservation.$(OBJEXT) \ + power_save.$(OBJEXT) powercapping.$(OBJEXT) preempt.$(OBJEXT) \ + proc_req.$(OBJEXT) read_config.$(OBJEXT) reservation.$(OBJEXT) \ sched_plugin.$(OBJEXT) sicp.$(OBJEXT) srun_comm.$(OBJEXT) \ state_save.$(OBJEXT) statistics.$(OBJEXT) step_mgr.$(OBJEXT) \ trigger_mgr.$(OBJEXT) @@ -512,6 +512,8 @@ slurmctld_SOURCES = \ port_mgr.c \ port_mgr.h \ power_save.c \ + powercapping.c \ + powercapping.h \ preempt.c \ preempt.h \ proc_req.c \ @@ -653,6 +655,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ping_nodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port_mgr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/power_save.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powercapping.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preempt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_req.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read_config.Po@am__quote@ diff --git a/src/slurmctld/job_mgr.c b/src/slurmctld/job_mgr.c index d1ee76ef34a17b43555573d6452d715ef7008ed1..737d92c9535d9f420afce1ee0c0c875144412eda 100644 --- a/src/slurmctld/job_mgr.c +++ b/src/slurmctld/job_mgr.c @@ -4030,7 +4030,9 @@ extern int job_allocate(job_desc_msg_t * job_specs, int immediate, (error_code == ESLURM_QOS_THRES) || (error_code == ESLURM_ACCOUNTING_POLICY) || (error_code == ESLURM_RESERVATION_NOT_USABLE) || - (error_code == ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE)) { + (error_code == ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE) || + (error_code == ESLURM_POWER_NOT_AVAIL) || + (error_code == ESLURM_POWER_RESERVED)) { /* Not fatal error, but job can't be scheduled right now */ if (immediate) { job_ptr->job_state = JOB_FAILED; diff --git a/src/slurmctld/job_scheduler.c b/src/slurmctld/job_scheduler.c index 8f30b39391a3449a4dacc297c88cf7835a8231d3..4d59f0e0f0d72931f891e8d01532184a9f2fddaf 100644 --- a/src/slurmctld/job_scheduler.c +++ b/src/slurmctld/job_scheduler.c @@ -1163,6 +1163,8 @@ static int _schedule(uint32_t job_limit) continue; if ((job_ptr->state_reason != WAIT_NO_REASON) && (job_ptr->state_reason != WAIT_RESOURCES) && + (job_ptr->state_reason != WAIT_POWER_NOT_AVAIL) && + (job_ptr->state_reason != WAIT_POWER_RESERVED) && (job_ptr->state_reason != WAIT_NODE_NOT_AVAIL)) continue; job_ptr->state_reason = WAIT_FRONT_END; @@ -1506,7 +1508,9 @@ next_task: error_code = select_nodes(job_ptr, false, NULL, unavail_node_str, NULL); - if (error_code == ESLURM_NODES_BUSY) { + if ((error_code == ESLURM_NODES_BUSY) || + (error_code == ESLURM_POWER_NOT_AVAIL) || + (error_code == ESLURM_POWER_RESERVED)) { debug3("sched: JobId=%u. State=%s. Reason=%s. " "Priority=%u. Partition=%s.", job_ptr->job_id, diff --git a/src/slurmctld/node_scheduler.c b/src/slurmctld/node_scheduler.c index fed981ab7c7dea4e0a9894ecd58c308c3dc69120..d98427db3152f7c427819479c9ab581edbcf3c0b 100644 --- a/src/slurmctld/node_scheduler.c +++ b/src/slurmctld/node_scheduler.c @@ -77,6 +77,7 @@ #include "src/slurmctld/job_scheduler.h" #include "src/slurmctld/licenses.h" #include "src/slurmctld/node_scheduler.h" +#include "src/slurmctld/powercapping.h" #include "src/slurmctld/preempt.h" #include "src/slurmctld/proc_req.h" #include "src/slurmctld/reservation.h" @@ -804,6 +805,7 @@ _get_req_features(struct node_set *node_set_ptr, int node_set_size, List preemptee_candidates = NULL; bool has_xand = false; bool resv_overlap = false; + uint32_t powercap; /* Mark nodes reserved for other jobs as off limit for this job. * If the job has a reservation, we've already limited the contents @@ -996,6 +998,7 @@ _get_req_features(struct node_set *node_set_ptr, int node_set_size, job_ptr->details->min_cpus = saved_min_cpus; job_ptr->details->min_nodes = saved_job_min_nodes; } + #if 0 { char *tmp_str = bitmap2node_name(job_ptr->details->req_node_bitmap); @@ -1025,6 +1028,76 @@ _get_req_features(struct node_set *node_set_ptr, int node_set_size, xfree(tmp_str); } #endif + + /* + * PowerCapping logic : now that we have the list of selected nodes + * we need to ensure that using this nodes respects the amount of + * available power as returned by the capping logic. + * If it is not the case, then ensure that the job stays pending + * by returning a relevant error code : + * ESLURM_POWER_NOT_AVAIL : if the current capping is blocking + * ESLURM_POWER_RESERVED : if the current capping and the power + * reservations are blocking + */ + if (error_code != SLURM_SUCCESS) { + debug3("powercapping: checking job %u : skipped, not eligible", + job_ptr->job_id); + } else if ((powercap = powercap_get_cluster_current_cap()) == 0) { + debug3("powercapping: checking job %u : skipped, capping " + "disabled", job_ptr->job_id); + } else if (!power_layout_ready()){ + debug3("powercapping:checking job %u : skipped, problems with" + "layouts, capping disabled", job_ptr->job_id); + } else { + uint32_t min_watts, max_watts, job_cap; + uint32_t cur_max_watts, tmp_max_watts; + bitstr_t *tmp_bitmap; + + /* + * get current powercapping logic state (min,cur,max) + */ + max_watts = powercap_get_cluster_max_watts(); + min_watts = powercap_get_cluster_min_watts(); + cur_max_watts = powercap_get_cluster_current_max_watts(); + /* in case of INFINITE cap, set it to max watts as it + * is done in the powercapping logic */ + if (powercap == INFINITE) + powercap = max_watts; + + /* build a temporary bitmap using idle_node_bitmap and + * remove the selected bitmap from this bitmap. + * Then compute the amount of power required for such a + * configuration to check that is is allowed by the current + * power cap */ + tmp_bitmap = bit_copy(idle_node_bitmap); + bit_not(*select_bitmap); + bit_and(tmp_bitmap, *select_bitmap); + bit_not(*select_bitmap); + tmp_max_watts = powercap_get_node_bitmap_maxwatts(tmp_bitmap); + bit_free(tmp_bitmap); + + /* get job cap based on power reservation on the system, + * if no reservation matches the job caracteristics, the + * powercap or the max_wattswill be returned. + * select the return code based on the impact of + * reservations on the failure */ + job_cap = powercap_get_job_cap(job_ptr, time(NULL)); + + if (tmp_max_watts > job_cap) { + FREE_NULL_BITMAP(*select_bitmap); + if (job_cap < powercap && + tmp_max_watts <= powercap) + error_code = ESLURM_POWER_RESERVED; + else + error_code = ESLURM_POWER_NOT_AVAIL; + } + debug2("powercapping: checking job %u : min=%u cur=%u " + "[new=%u] [resv_cap=%u] [cap=%u] max=%u : %s", + job_ptr->job_id, min_watts, cur_max_watts, + tmp_max_watts, job_cap, powercap, max_watts, + slurm_strerror(error_code)); + } + if (preemptee_candidates) list_destroy(preemptee_candidates); @@ -1873,9 +1946,16 @@ extern int select_nodes(struct job_record *job_ptr, bool test_only, (job_ptr->state_reason == WAIT_BLOCK_D_ACTION)) { /* state_reason was already setup */ } else { - job_ptr->state_reason = WAIT_RESOURCES; + if (error_code == ESLURM_POWER_NOT_AVAIL) + job_ptr->state_reason = WAIT_POWER_NOT_AVAIL; + else if (error_code == ESLURM_POWER_RESERVED) + job_ptr->state_reason = WAIT_POWER_RESERVED; + else + job_ptr->state_reason = WAIT_RESOURCES; xfree(job_ptr->state_desc); - if (error_code == ESLURM_NODES_BUSY) + if ((error_code == ESLURM_NODES_BUSY) || + (error_code == ESLURM_POWER_NOT_AVAIL) || + (error_code == ESLURM_POWER_RESERVED)) slurm_sched_g_job_is_pending(); } goto cleanup; diff --git a/src/slurmctld/powercapping.c b/src/slurmctld/powercapping.c new file mode 100644 index 0000000000000000000000000000000000000000..bf36a29b45a8a7f59dab84d8c69edce61a241fac --- /dev/null +++ b/src/slurmctld/powercapping.c @@ -0,0 +1,326 @@ +/*****************************************************************************\ + * powercapping.c - Definitions for power capping logic in the controller + ***************************************************************************** + * Copyright (C) 2013 CEA/DAM/DIF + * Written by Matthieu Hautreux <matthieu.hautreux@cea.fr> + * + * Copyright (C) 2014 Bull S.A.S. + * Written by Yiannis Georgiou <yiannis.georgiou@bull.net> + * + * This file is part of SLURM, a resource management program. + * For details, see <http://slurm.schedmd.com/>. + * 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. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * 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. +\*****************************************************************************/ +#include <stdlib.h> +#include <string.h> + +#include "src/common/bitstring.h" +#include "src/common/layouts_mgr.h" +#include "src/common/node_conf.h" +#include "src/common/power.h" +#include "src/common/slurm_protocol_api.h" +#include "src/common/xstring.h" +#include "src/slurmctld/powercapping.h" +#include "src/slurmctld/reservation.h" +#include "src/slurmctld/slurmctld.h" + +#define L_POWER "power" +#define L_CLUSTER "Cluster" +#define L_SUM_MAX "MaxSumWatts" +#define L_SUM_IDLE "IdleSumWatts" +#define L_SUM_CUR "CurrentSumPower" +#define L_NODE_MAX "MaxWatts" +#define L_NODE_IDLE "IdleWatts" +#define L_NODE_DOWN "DownWatts" +#define L_NODE_SAVE "PowerSaveWatts" +#define L_NODE_CUR "CurrentPower" + +static bool _powercap_enabled(void) +{ + if (powercap_get_cluster_current_cap() == 0) + return false; + return true; +} + +bool power_layout_ready(void) +{ + static time_t last_error_time = (time_t) 0; + time_t now = time(NULL); + struct node_record *node_ptr; + uint32_t data[2]; + int i; + + for (i = 0, node_ptr = node_record_table_ptr; i < node_record_count; + i++, node_ptr++) { + if (layouts_entity_get_mkv(L_POWER, node_ptr->name, + "MaxWatts,IdleWatts", data, (sizeof(uint32_t) * 2), + L_T_UINT32)) { + /* Limit error message frequency, once per minute */ + if (difftime(now, last_error_time) < 60) + return false; + last_error_time = now; + error("%s: node %s is not in the layouts.d/power.conf file", + __func__, node_ptr->name); + return false; + } + } + return true; +} + + +uint32_t powercap_get_cluster_max_watts(void) +{ + uint32_t max_watts; + + if (!_powercap_enabled()) + return 0; + + if (!power_layout_ready()) + return 0; + + layouts_entity_pullget_kv(L_POWER, L_CLUSTER, L_SUM_MAX, &max_watts, + L_T_UINT32); + + return max_watts; +} + +uint32_t powercap_get_cluster_min_watts(void) +{ + uint32_t min_watts = 0, tmp_watts, save_watts, down_watts; + struct node_record *node_ptr; + int i; + + if (!_powercap_enabled()) + return 0; + + if (!power_layout_ready()) + return 0; + + for (i = 0, node_ptr = node_record_table_ptr; i < node_record_count; + i++, node_ptr++) { + layouts_entity_pullget_kv(L_POWER, node_ptr->name, L_NODE_IDLE, + &tmp_watts, L_T_UINT32); + layouts_entity_pullget_kv(L_POWER, node_ptr->name, L_NODE_DOWN, + &down_watts, L_T_UINT32); + tmp_watts = MIN(tmp_watts, down_watts); + layouts_entity_pullget_kv(L_POWER, node_ptr->name, L_NODE_SAVE, + &save_watts, L_T_UINT32); + tmp_watts = MIN(tmp_watts, save_watts); + min_watts += tmp_watts; + } + + return min_watts; +} + +uint32_t powercap_get_cluster_current_cap(void) +{ + char *end_ptr = NULL, *sched_params, *tmp_ptr; + uint32_t cap_watts = 0; + + sched_params = slurm_get_power_parameters(); + if (!sched_params) + return cap_watts; + + if ((tmp_ptr = strstr(sched_params, "cap_watts=INFINITE"))) { + cap_watts = INFINITE; + } else if ((tmp_ptr = strstr(sched_params, "cap_watts=UNLIMITED"))) { + cap_watts = INFINITE; + } else if ((tmp_ptr = strstr(sched_params, "cap_watts="))) { + cap_watts = strtol(tmp_ptr + 10, &end_ptr, 10); + if ((end_ptr[0] == 'k') || (end_ptr[0] == 'K')) { + cap_watts *= 1000; + } else if ((end_ptr[0] == 'm') || (end_ptr[0] == 'M')) { + cap_watts *= 1000000; + } + } + xfree(sched_params); + + return cap_watts; +} + +/* Strip "cap_watts=..." pointed to by tmp_ptr out of the string by shifting + * other string contents down over it. */ +static void _strip_cap_watts(char *tmp_ptr) +{ + char *end_ptr; + int i; + + end_ptr = strchr(tmp_ptr, ','); + if (!end_ptr) { + tmp_ptr[0] = '\0'; + return; + } + end_ptr++; + for (i = 0; ; i++) { + tmp_ptr[i] = end_ptr[i]; + if (tmp_ptr[i] == '\0') + break; + } + +} + +int powercap_set_cluster_cap(uint32_t new_cap) +{ + char *sched_params, *sep, *tmp_ptr; + + sched_params = slurm_get_power_parameters(); + if (sched_params) { + while ((tmp_ptr = strstr(sched_params, "cap_watts="))) { + _strip_cap_watts(tmp_ptr); + } + } + if (sched_params && sched_params[0]) + sep = ","; + else + sep = ""; + if (new_cap == INFINITE) + xstrfmtcat(sched_params, "%scap_watts=INFINITE", sep); + else + xstrfmtcat(sched_params, "%scap_watts=%u", sep, new_cap); + slurm_set_power_parameters(sched_params); + power_g_reconfig(); + xfree(sched_params); + + return 0; +} + +uint32_t powercap_get_cluster_adjusted_max_watts(void) +{ + uint32_t adj_max_watts = 0,val; + struct node_record *node_ptr; + int i; + + if (!_powercap_enabled()) + return 0; + if (!power_layout_ready()) + return 0; + for (i = 0, node_ptr = node_record_table_ptr; i < node_record_count; + i++, node_ptr++) { + if (bit_test(power_node_bitmap, i)) { + layouts_entity_pullget_kv(L_POWER, node_ptr->name, + L_NODE_SAVE, &val, L_T_UINT32); + } else if (!bit_test(up_node_bitmap, i)) { + layouts_entity_pullget_kv(L_POWER, node_ptr->name, + L_NODE_DOWN, &val, L_T_UINT32); + } else { + layouts_entity_pullget_kv(L_POWER, node_ptr->name, + L_NODE_MAX, &val, L_T_UINT32); + } + adj_max_watts += val; + } + + return adj_max_watts; +} + +uint32_t powercap_get_cluster_current_max_watts(void) +{ + uint32_t cur_max_watts = 0; + + if (!_powercap_enabled()) + return 0; + if (!power_layout_ready()) + return 0; + + cur_max_watts = powercap_get_node_bitmap_maxwatts(NULL); + return cur_max_watts; +} + +uint32_t powercap_get_node_bitmap_maxwatts(bitstr_t *idle_bitmap) +{ + uint32_t max_watts = 0, val; + struct node_record *node_ptr; + int i; + bitstr_t *tmp_bitmap = NULL; + + if (!_powercap_enabled()) + return 0; + if (!power_layout_ready()) + return 0; + + /* if no input bitmap, consider the current idle nodes + * bitmap as the input bitmap tagging nodes to consider + * as idle while computing the max watts of the cluster */ + if (idle_bitmap == NULL) { + tmp_bitmap = bit_copy(idle_node_bitmap); + idle_bitmap = tmp_bitmap; + } + + for (i = 0, node_ptr = node_record_table_ptr; i < node_record_count; + i++, node_ptr++) { + /* non reserved node, evaluate the different cases */ + if (bit_test(idle_bitmap, i)) { + /* idle nodes, 2 cases : power save or not */ + if (bit_test(power_node_bitmap, i)) { + layouts_entity_pullget_kv(L_POWER, + node_ptr->name, L_NODE_SAVE, + &val, L_T_UINT32); + } else { + layouts_entity_pullget_kv(L_POWER, + node_ptr->name, L_NODE_IDLE, + &val, L_T_UINT32); + } + } else { + /* non idle nodes, 2 cases : down or not */ + if (!bit_test(up_node_bitmap, i)) { + layouts_entity_pullget_kv(L_POWER, + node_ptr->name, L_NODE_DOWN, + &val, L_T_UINT32); + } else { + layouts_entity_pullget_kv(L_POWER, + node_ptr->name, L_NODE_MAX, + &val, L_T_UINT32); + } + } + max_watts += val; + } + + if (tmp_bitmap) + bit_free(tmp_bitmap); + + return max_watts; +} + +uint32_t powercap_get_job_cap(struct job_record *job_ptr, time_t when) +{ + uint32_t powercap = 0, resv_watts; + + powercap = powercap_get_cluster_current_cap(); + if (powercap == INFINITE) + powercap = powercap_get_cluster_max_watts(); + if (powercap == 0) + return 0; /* should not happened */ + + /* get the amount of watts reserved for the job */ + resv_watts = job_test_watts_resv(job_ptr, when); + + /* avoid underflow of the cap value, return at least 0 */ + if (resv_watts > powercap) + resv_watts = powercap; + + return (powercap - resv_watts); +} diff --git a/src/slurmctld/powercapping.h b/src/slurmctld/powercapping.h new file mode 100644 index 0000000000000000000000000000000000000000..028172259d83c09ac99573e73f2ba90ecae5cfba --- /dev/null +++ b/src/slurmctld/powercapping.h @@ -0,0 +1,115 @@ +/*****************************************************************************\ + * powercapping.h - Definitions for power capping logic in the controller + ***************************************************************************** + * Copyright (C) 2013 CEA/DAM/DIF + * Written by Matthieu Hautreux <matthieu.hautreux@cea.fr> + * + * This file is part of SLURM, a resource management program. + * For details, see <http://slurm.schedmd.com/>. + * 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. + * + * In addition, as a special exception, the copyright holders give permission + * to link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. You must obey the GNU + * General Public License in all respects for all of the code used other than + * OpenSSL. If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not obligated to do + * so. If you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files in + * the program, then also delete it here. + * + * 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. +\*****************************************************************************/ + +#ifndef _POWERCAPPING_H +#define _POWERCAPPING_H + +#include <stdint.h> +#include <time.h> +#include "src/slurmctld/slurmctld.h" + +/** + * powercap_get_cluster_max_watts + * return the max power consumption of the cluster + * RET uint32_t - the max consumption in watts + */ +uint32_t powercap_get_cluster_max_watts(void); + +/** + * powercap_get_cluster_min_watts + * return the min power consumption of the cluster + * RET uint32_t - the min consumption in watts + */ +uint32_t powercap_get_cluster_min_watts(void); + +/** + * powercap_get_cluster_current_cap + * return the current powercap value + * RET uint32_t - powercap + */ +uint32_t powercap_get_cluster_current_cap(void); + +/** + * powercap_set_cluster_cap + * set a new powercap value + * IN uint32_t - new_cap + * RET int - 0 or error code + */ +int powercap_set_cluster_cap(uint32_t new_cap); + +/** + * powercap_get_cluster_adjusted_max_watts + * return max power consumption of the cluster, + * taking into consideration the nodes which are POWERED DOWN + * RET uint32_t - the max consumption in watts + */ +uint32_t powercap_get_cluster_adjusted_max_watts(void); + +/** + * powercap_get_cluster_current_max_watts + * return current max power consumption of the cluster, + * taking into consideration the nodes which are POWERED DOWN + * and the nodes which are idle + * RET uint32_t - the max consumption in watts + */ +uint32_t powercap_get_cluster_current_max_watts(void); + +/** + * powercap_get_node_bitmap_maxwatt + * return current max consumption value of the cluster, + * taking into consideration the nodes which are POWERED DOWN + * and the nodes which are idle using the input bitmap to identify + * them. + * A null argument means, use the controller idle_node_bitmap instead. + * IN bitstr_t* idle_bitmap + * RET uint32_t - the max consumption in watts + */ +uint32_t powercap_get_node_bitmap_maxwatts(bitstr_t* select_bitmap); + +/** + * powercap_get_job_cap + * return the cap value of a job taking into account the current cap + * as well as the power reservations defined on the interval + * + * IN struct job_record* job_ptr + * IN time_t when + * RET uint32_t - the cap the job is restricted to + */ +uint32_t powercap_get_job_cap(struct job_record *job_ptr, time_t when); + +bool power_layout_ready(void); + +#endif /* !_POWERCAPPING_H */ diff --git a/src/slurmctld/proc_req.c b/src/slurmctld/proc_req.c index 6b94a303ddeb742cbae34af3d3c11e46e6686bba..18fb4dda10c78dbc10f2fdf606baf05468a6d2dd 100644 --- a/src/slurmctld/proc_req.c +++ b/src/slurmctld/proc_req.c @@ -60,22 +60,22 @@ #include "src/common/forward.h" #include "src/common/gres.h" #include "src/common/hostlist.h" +#include "src/common/layouts_mgr.h" #include "src/common/log.h" #include "src/common/macros.h" #include "src/common/node_select.h" #include "src/common/pack.h" #include "src/common/read_config.h" +#include "src/common/slurm_acct_gather.h" #include "src/common/slurm_auth.h" #include "src/common/slurm_cred.h" +#include "src/common/slurm_ext_sensors.h" #include "src/common/slurm_priority.h" #include "src/common/slurm_protocol_api.h" +#include "src/common/slurm_protocol_interface.h" #include "src/common/slurm_topology.h" #include "src/common/switch.h" #include "src/common/xstring.h" -#include "src/common/slurm_ext_sensors.h" -#include "src/common/slurm_acct_gather.h" -#include "src/common/slurm_protocol_interface.h" -#include "src/common/layouts_mgr.h" #include "src/slurmctld/agent.h" #include "src/slurmctld/burst_buffer.h" @@ -84,6 +84,7 @@ #include "src/slurmctld/job_scheduler.h" #include "src/slurmctld/licenses.h" #include "src/slurmctld/locks.h" +#include "src/slurmctld/powercapping.h" #include "src/slurmctld/proc_req.h" #include "src/slurmctld/read_config.h" #include "src/slurmctld/reservation.h" @@ -151,6 +152,7 @@ inline static void _slurm_rpc_epilog_complete(slurm_msg_t * msg, bool running_composite); inline static void _slurm_rpc_get_shares(slurm_msg_t *msg); inline static void _slurm_rpc_get_topo(slurm_msg_t * msg); +inline static void _slurm_rpc_get_powercap(slurm_msg_t * msg); inline static void _slurm_rpc_get_priority_factors(slurm_msg_t *msg); inline static void _slurm_rpc_job_notify(slurm_msg_t * msg); inline static void _slurm_rpc_job_ready(slurm_msg_t * msg); @@ -194,6 +196,7 @@ inline static void _slurm_rpc_update_job(slurm_msg_t * msg); inline static void _slurm_rpc_update_node(slurm_msg_t * msg); inline static void _slurm_rpc_update_layout(slurm_msg_t * msg); inline static void _slurm_rpc_update_partition(slurm_msg_t * msg); +inline static void _slurm_rpc_update_powercap(slurm_msg_t * msg); inline static void _slurm_rpc_update_block(slurm_msg_t * msg); inline static void _slurm_rpc_dump_cache(slurm_msg_t * msg); inline static void _update_cred_key(void); @@ -417,6 +420,10 @@ void slurmctld_req(slurm_msg_t *msg, connection_arg_t *arg) _slurm_rpc_update_partition(msg); slurm_free_update_part_msg(msg->data); break; + case REQUEST_UPDATE_POWERCAP: + _slurm_rpc_update_powercap(msg); + slurm_free_powercap_info_msg(msg->data); + break; case REQUEST_DELETE_PARTITION: _slurm_rpc_delete_partition(msg); slurm_free_delete_part_msg(msg->data); @@ -542,6 +549,10 @@ void slurmctld_req(slurm_msg_t *msg, connection_arg_t *arg) _slurm_rpc_get_topo(msg); /* No body to free */ break; + case REQUEST_POWERCAP_INFO: + _slurm_rpc_get_powercap(msg); + /* No body to free */ + break; case REQUEST_SPANK_ENVIRONMENT: _slurm_rpc_dump_spank(msg); slurm_free_spank_env_request_msg(msg->data); @@ -1085,6 +1096,8 @@ static void _slurm_rpc_allocate_resources(slurm_msg_t * msg) /* return result */ if ((error_code == ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE) || + (error_code == ESLURM_POWER_NOT_AVAIL) || + (error_code == ESLURM_POWER_RESERVED) || (error_code == ESLURM_RESERVATION_NOT_USABLE) || (error_code == ESLURM_QOS_THRES) || (error_code == ESLURM_NODE_NOT_AVAIL) || @@ -3393,7 +3406,9 @@ static void _slurm_rpc_submit_batch_job(slurm_msg_t * msg) (error_code != ESLURM_NODE_NOT_AVAIL) && (error_code != ESLURM_QOS_THRES) && (error_code != ESLURM_RESERVATION_NOT_USABLE) && - (error_code != ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE)) { + (error_code != ESLURM_REQUESTED_PART_CONFIG_UNAVAILABLE) && + (error_code != ESLURM_POWER_NOT_AVAIL) && + (error_code != ESLURM_POWER_RESERVED)) { info("_slurm_rpc_submit_batch_job: %s", slurm_strerror(error_code)); if (err_msg) @@ -3705,6 +3720,74 @@ static void _slurm_rpc_update_partition(slurm_msg_t * msg) } } +/* _slurm_rpc_update_powercap - process RPC to update the powercap */ +static void _slurm_rpc_update_powercap(slurm_msg_t * msg) +{ + int error_code = SLURM_SUCCESS; + DEF_TIMERS; + bool valid_cap = false; + uint32_t min, max, orig_cap; + update_powercap_msg_t *ptr = (update_powercap_msg_t *) msg->data; + + /* Locks: write configuration, read node */ + slurmctld_lock_t config_write_lock = { + WRITE_LOCK, NO_LOCK, READ_LOCK, NO_LOCK }; + uid_t uid = g_slurm_auth_get_uid(msg->auth_cred, NULL); + + START_TIMER; + debug2("Processing RPC: REQUEST_UPDATE_POWERCAP from uid=%d", uid); + if (!validate_super_user(uid)) { + error_code = ESLURM_USER_ID_MISSING; + error("Security violation, UPDATE_POWERCAP RPC from uid=%d", + uid); + } + + if (error_code == SLURM_SUCCESS) { + /* do RPC call */ + lock_slurmctld(config_write_lock); + if (ptr->power_cap == 0 || + ptr->power_cap == INFINITE) { + valid_cap = true; + } else if (!power_layout_ready()) { + /* Not using layouts/power framework */ + valid_cap = true; + } else { + /* we need to set a cap if + * the current value is 0 in order to + * enable the capping system and get + * the min and max values */ + orig_cap = powercap_get_cluster_current_cap(); + powercap_set_cluster_cap(INFINITE); + min = powercap_get_cluster_min_watts(); + max = powercap_get_cluster_max_watts(); + if (min <= ptr->power_cap && max >= ptr->power_cap) + valid_cap = true; + else + powercap_set_cluster_cap(orig_cap); + } + if (valid_cap) + powercap_set_cluster_cap(ptr->power_cap); + else + error_code = ESLURM_INVALID_POWERCAP; + unlock_slurmctld(config_write_lock); + END_TIMER2("_slurm_rpc_update_powercap"); + } + + /* return result */ + if (error_code) { + info("_slurm_rpc_update_powercap: %s", + slurm_strerror(error_code)); + slurm_send_rc_msg(msg, error_code); + } else { + debug2("_slurm_rpc_update_powercap complete %s", TIME_STR); + slurm_send_rc_msg(msg, SLURM_SUCCESS); + + /* NOTE: These functions provide their own locks */ + schedule(0); + save_all_state(); + } +} + /* _slurm_rpc_delete_partition - process RPC to delete a partition */ static void _slurm_rpc_delete_partition(slurm_msg_t * msg) { @@ -4781,6 +4864,37 @@ inline static void _slurm_rpc_get_topo(slurm_msg_t * msg) slurm_free_topo_info_msg(topo_resp_msg); } +inline static void _slurm_rpc_get_powercap(slurm_msg_t * msg) +{ + powercap_info_msg_t *powercap_resp_msg, *ptr; + slurm_msg_t response_msg; + /* Locks: read config lock */ + slurmctld_lock_t config_read_lock = { + READ_LOCK, NO_LOCK, NO_LOCK, NO_LOCK }; + DEF_TIMERS; + + START_TIMER; + lock_slurmctld(config_read_lock); + powercap_resp_msg = xmalloc(sizeof(powercap_info_msg_t)); + ptr = powercap_resp_msg; + ptr->power_cap = powercap_get_cluster_current_cap(); + ptr->min_watts = powercap_get_cluster_min_watts(); + ptr->cur_max_watts = powercap_get_cluster_current_max_watts(); + ptr->adj_max_watts = powercap_get_cluster_adjusted_max_watts(); + ptr->max_watts = powercap_get_cluster_max_watts(); + unlock_slurmctld(config_read_lock); + END_TIMER2("_slurm_rpc_get_powercap"); + + slurm_msg_t_init(&response_msg); + response_msg.flags = msg->flags; + response_msg.protocol_version = msg->protocol_version; + response_msg.address = msg->address; + response_msg.msg_type = RESPONSE_POWERCAP_INFO; + response_msg.data = powercap_resp_msg; + slurm_send_node_msg(msg->conn_fd, &response_msg); + slurm_free_powercap_info_msg(powercap_resp_msg); +} + inline static void _slurm_rpc_job_notify(slurm_msg_t * msg) { int error_code; diff --git a/src/slurmctld/reservation.c b/src/slurmctld/reservation.c index 139960d21f7b84bd1854287c45df5a82a538d50f..2625d47a5ed6249f5478eed92b104e341f0bdb92 100644 --- a/src/slurmctld/reservation.c +++ b/src/slurmctld/reservation.c @@ -106,6 +106,34 @@ uint32_t cnodes_per_mp = 0; uint32_t cpus_per_mp = 0; #endif +/* + * the two following structs enable to build a + * planning of a constraint evolution over time + * taking into account temporal overlapping + */ +typedef struct constraint_planning { + List slot_list; +} constraint_planning_t; + +typedef struct constraint_slot { + time_t start; + time_t end; + uint32_t value; +} constraint_slot_t; +/* + * the associated functions are the following + */ +static void _free_slot(void *x); +static void _init_constraint_planning(constraint_planning_t* sched); +static void _print_constraint_planning(constraint_planning_t* sched); +static void _free_constraint_planning(constraint_planning_t* sched); +static void _update_constraint_planning(constraint_planning_t* sched, + uint32_t value, time_t start, + time_t end); +static uint32_t _max_constraint_planning(constraint_planning_t* sched, + time_t *start, time_t *end); + + static void _advance_resv_time(slurmctld_resv_t *resv_ptr); static void _advance_time(time_t *res_time, int day_cnt); static int _build_account_list(char *accounts, int *account_cnt, @@ -218,7 +246,7 @@ static slurmctld_resv_t *_copy_resv(slurmctld_resv_t *resv_orig_ptr) resv_copy_ptr->account_list = xmalloc(sizeof(char *) * resv_orig_ptr->account_cnt); resv_copy_ptr->account_not = resv_orig_ptr->account_not; - for (i=0; i<resv_copy_ptr->account_cnt; i++) { + for (i = 0; i < resv_copy_ptr->account_cnt; i++) { resv_copy_ptr->account_list[i] = xstrdup(resv_orig_ptr->account_list[i]); } @@ -241,12 +269,16 @@ static slurmctld_resv_t *_copy_resv(slurmctld_resv_t *resv_orig_ptr) resv_copy_ptr->magic = resv_orig_ptr->magic; resv_copy_ptr->flags_set_node = resv_orig_ptr->flags_set_node; resv_copy_ptr->name = xstrdup(resv_orig_ptr->name); - resv_copy_ptr->node_bitmap = bit_copy(resv_orig_ptr->node_bitmap); + if (resv_orig_ptr->node_bitmap) { + resv_copy_ptr->node_bitmap = + bit_copy(resv_orig_ptr->node_bitmap); + } resv_copy_ptr->node_cnt = resv_orig_ptr->node_cnt; resv_copy_ptr->node_list = xstrdup(resv_orig_ptr->node_list); resv_copy_ptr->partition = xstrdup(resv_orig_ptr->partition); resv_copy_ptr->part_ptr = resv_orig_ptr->part_ptr; resv_copy_ptr->resv_id = resv_orig_ptr->resv_id; + resv_copy_ptr->resv_watts = resv_orig_ptr->resv_watts; resv_copy_ptr->start_time = resv_orig_ptr->start_time; resv_copy_ptr->start_time_first = resv_orig_ptr->start_time_first; resv_copy_ptr->start_time_prev = resv_orig_ptr->start_time_prev; @@ -257,7 +289,7 @@ static slurmctld_resv_t *_copy_resv(slurmctld_resv_t *resv_orig_ptr) resv_copy_ptr->user_list = xmalloc(sizeof(uid_t) * resv_orig_ptr->user_cnt); resv_copy_ptr->user_not = resv_orig_ptr->user_not; - for (i=0; i<resv_copy_ptr->user_cnt; i++) + for (i = 0; i < resv_copy_ptr->user_cnt; i++) resv_copy_ptr->user_list[i] = resv_orig_ptr->user_list[i]; return resv_copy_ptr; @@ -343,6 +375,7 @@ static void _restore_resv(slurmctld_resv_t *dest_resv, dest_resv->part_ptr = src_resv->part_ptr; dest_resv->resv_id = src_resv->resv_id; + dest_resv->resv_watts = src_resv->resv_watts; dest_resv->start_time = src_resv->start_time; dest_resv->start_time_first = src_resv->start_time_first; dest_resv->start_time_prev = src_resv->start_time_prev; @@ -425,6 +458,7 @@ static void _dump_resv_req(resv_desc_msg_t *resv_ptr, char *mode) { char start_str[32] = "-1", end_str[32] = "-1", *flag_str = NULL; + char watts_str[32] = "n/a"; char *node_cnt_str = NULL; int duration, i; @@ -439,6 +473,10 @@ static void _dump_resv_req(resv_desc_msg_t *resv_ptr, char *mode) slurm_make_time_str(&resv_ptr->end_time, end_str, sizeof(end_str)); } + if (resv_ptr->resv_watts != NO_VAL) { + snprintf(watts_str, sizeof(watts_str), "%u", + resv_ptr->resv_watts); + } if (resv_ptr->flags != NO_VAL) flag_str = reservation_flags_string(resv_ptr->flags); @@ -461,12 +499,13 @@ static void _dump_resv_req(resv_desc_msg_t *resv_ptr, char *mode) info("%s: Name=%s StartTime=%s EndTime=%s Duration=%d " "Flags=%s NodeCnt=%s NodeList=%s Features=%s " - "PartitionName=%s Users=%s Accounts=%s Licenses=%s BurstBuffer=%s", + "PartitionName=%s Users=%s Accounts=%s Licenses=%s BurstBuffer=%s" + "Watts=%s", mode, resv_ptr->name, start_str, end_str, duration, flag_str, node_cnt_str, resv_ptr->node_list, resv_ptr->features, resv_ptr->partition, resv_ptr->users, resv_ptr->accounts, resv_ptr->licenses, - resv_ptr->burst_buffer); + resv_ptr->burst_buffer, watts_str); xfree(flag_str); xfree(node_cnt_str); @@ -1343,6 +1382,7 @@ static void _pack_resv(slurmctld_resv_t *resv_ptr, Buf buffer, pack32(resv_ptr->node_cnt, buffer); packstr(resv_ptr->node_list, buffer); packstr(resv_ptr->partition, buffer); + pack32(resv_ptr->resv_watts, buffer); pack_time(start_relative, buffer); packstr(resv_ptr->tres_fmt_str, buffer); packstr(resv_ptr->users, buffer); @@ -1427,6 +1467,7 @@ slurmctld_resv_t *_load_reservation_state(Buf buffer, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&resv_ptr->partition, &uint32_tmp, buffer); + safe_unpack32(&resv_ptr->resv_watts, buffer); safe_unpack_time(&resv_ptr->start_time_first, buffer); safe_unpackstr_xmalloc(&resv_ptr->tres_fmt_str, &uint32_tmp, buffer); @@ -1732,11 +1773,11 @@ static void _set_tres_cnt(slurmctld_resv_t *resv_ptr, name2 = val2 = ""; info("sched: %s reservation=%s%s%s%s%s nodes=%s cores=%u " - "licenses=%s tres=%s start=%s end=%s", + "licenses=%s tres=%s watts=%u start=%s end=%s", old_resv_ptr ? "Updated" : "Created", resv_ptr->name, name1, val1, name2, val2, resv_ptr->node_list, resv_ptr->core_cnt, resv_ptr->licenses, - resv_ptr->tres_str, + resv_ptr->tres_str, resv_ptr->resv_watts, start_time, end_time); if (old_resv_ptr) _post_resv_update(resv_ptr, old_resv_ptr); @@ -2152,6 +2193,7 @@ extern int create_resv(resv_desc_msg_t *resv_desc_ptr) resv_ptr->partition = resv_desc_ptr->partition; resv_desc_ptr->partition = NULL; /* Nothing left to free */ resv_ptr->part_ptr = part_ptr; + resv_ptr->resv_watts = resv_desc_ptr->resv_watts; resv_ptr->start_time = resv_desc_ptr->start_time; resv_ptr->start_time_first = resv_ptr->start_time; resv_ptr->start_time_prev = resv_ptr->start_time; @@ -2317,6 +2359,8 @@ extern int update_resv(resv_desc_msg_t *resv_desc_ptr) resv_desc_ptr->partition = NULL; /* Nothing left to free */ resv_ptr->part_ptr = part_ptr; } + if (resv_desc_ptr->resv_watts != NO_VAL) + resv_ptr->resv_watts = resv_desc_ptr->resv_watts; if (resv_desc_ptr->accounts) { rc = _update_account_list(resv_ptr, resv_desc_ptr->accounts); if (rc) { @@ -4337,6 +4381,228 @@ extern int job_test_lic_resv(struct job_record *job_ptr, char *lic_name, return resv_cnt; } + +static void _free_slot(void *x) +{ + xfree(x); +} + +static void _init_constraint_planning(constraint_planning_t* sched) +{ + sched->slot_list = list_create(_free_slot); +} + +static void _free_constraint_planning(constraint_planning_t* sched) +{ + list_destroy(sched->slot_list); +} + +/* + * update the list of slots with the new time delimited constraint + * the new slot may have to be : + * - inserted + * - added to a previously added slot, if it corresponds to the same + * period + * - shrinked if it overlaps temporarily a previously slot + * (in that case it will result in a new slot insertion and an + * already defined slot update with the addition of the value) + * - splitted in two chunks if it is nested in a previously slot + * (in that case it will result in the insertion of new head, + * the update of the previously defined slot, and the iteration + * of the logic with a new slot reduced to the remaining time) + */ +static void _update_constraint_planning(constraint_planning_t* sched, + uint32_t value, + time_t start, time_t end) +{ + ListIterator iter; + constraint_slot_t *cur_slot, *cstr_slot, *tmp_slot; + bool done = false; + + /* create the constraint slot to add */ + cstr_slot = xmalloc(sizeof(constraint_slot_t)); + cstr_slot->value = value; + cstr_slot->start = start; + cstr_slot->end = end; + + /* iterate on the current slot list to identify + * the modifications and do them live */ + iter = list_iterator_create(sched->slot_list); + while ((cur_slot = (constraint_slot_t *) list_next(iter))) { + /* cur_slot is posterior or contiguous, insert cstr, + * mark the state as done and break */ + if (cstr_slot->end <= cur_slot->start) { + list_insert(iter,cstr_slot); + done = true; + break; + } + /* cur_slot has the same time period, update it, + * mark the state as done and break */ + if (cstr_slot->start == cur_slot->start && + cstr_slot->end == cur_slot->end) { + cur_slot->value += cstr_slot->value; + xfree(cstr_slot); + done = true; + break; + } + /* cur_slot is anterior or contiguous, continue */ + if (cur_slot->end <= cstr_slot->start) + continue; + /* new slot starts after this one */ + if (cur_slot->start <= cstr_slot->start) { + /* we may need up to 2 insertions and one update */ + if (cur_slot->start < cstr_slot->start) { + tmp_slot = xmalloc(sizeof(constraint_slot_t)); + tmp_slot->value = cur_slot->value; + tmp_slot->start = cur_slot->start; + tmp_slot->end = cstr_slot->start; + list_insert(iter,tmp_slot); + cur_slot->start = tmp_slot->end; + } + if (cstr_slot->end < cur_slot->end) { + cstr_slot->value += cur_slot->value; + list_insert(iter,cstr_slot); + cur_slot->start = cstr_slot->end; + } else if (cstr_slot->end > cur_slot->end) { + cur_slot->value += cstr_slot->value; + cstr_slot->start = cur_slot->end; + continue; + } else { + cur_slot->value += cstr_slot->value; + xfree(cstr_slot); + } + done = true; + break; + } else { + /* new slot starts before, and we know that it is + * not contiguous (previously checked) */ + tmp_slot = xmalloc(sizeof(constraint_slot_t)); + tmp_slot->value = cstr_slot->value; + tmp_slot->start = cstr_slot->start; + tmp_slot->end = cur_slot->start; + list_insert(iter,tmp_slot); + if (cstr_slot->end == cur_slot-> end) { + cur_slot->value += cstr_slot->value; + xfree(cstr_slot); + done = true; + break; + } else if (cstr_slot->end < cur_slot-> end) { + cstr_slot->start = cur_slot->start; + cstr_slot->value += cur_slot->value; + list_insert(iter,cstr_slot); + cur_slot->start = cstr_slot->end; + done = true; + break; + } else { + cur_slot->value += cstr_slot->value; + cstr_slot->start = cur_slot->end; + continue; + } + } + } + list_iterator_destroy(iter); + + /* we might still need to add the [updated] constrain slot */ + if (!done) + list_append(sched->slot_list, cstr_slot); +} + +static uint32_t _max_constraint_planning(constraint_planning_t* sched, + time_t *start, time_t *end) +{ + ListIterator iter; + constraint_slot_t *cur_slot; + uint32_t max = 0; + + iter = list_iterator_create(sched->slot_list); + while ((cur_slot = (constraint_slot_t *) list_next(iter))) { + if (cur_slot->value > max) { + max = cur_slot->value; + *start = cur_slot->start; + *end = cur_slot->end; + } + } + list_iterator_destroy(iter); + + return max; +} + +static void _print_constraint_planning(constraint_planning_t* sched) +{ + ListIterator iter; + constraint_slot_t *cur_slot; + char start_str[32] = "-1", end_str[32] = "-1"; + uint32_t i = 0; + + iter = list_iterator_create(sched->slot_list); + while ((cur_slot = (constraint_slot_t *) list_next(iter))) { + slurm_make_time_str(&cur_slot->start, + start_str, sizeof(start_str)); + slurm_make_time_str(&cur_slot->end, + end_str, sizeof(end_str)); + debug2("constraint_planning: slot[%u]: %s to %s count=%u", + i, start_str, end_str, cur_slot->value); + i++; + } + list_iterator_destroy(iter); +} + +/* + * Determine how many watts the specified job is prevented from using + * due to reservations + * + * IN job_ptr - job to test + * IN when - when the job is expected to start + * RET amount of watts the job is prevented from using + */ +extern uint32_t job_test_watts_resv(struct job_record *job_ptr, time_t when) +{ + slurmctld_resv_t * resv_ptr; + time_t job_start_time, job_end_time, now = time(NULL); + ListIterator iter; + constraint_planning_t wsched; + time_t start, end; + char start_str[32] = "-1", end_str[32] = "-1"; + uint32_t resv_cnt = 0; + + _init_constraint_planning(&wsched); + + job_start_time = when; + job_end_time = when + _get_job_duration(job_ptr); + iter = list_iterator_create(resv_list); + while ((resv_ptr = (slurmctld_resv_t *) list_next(iter))) { + if (resv_ptr->end_time <= now) + _advance_resv_time(resv_ptr); + if (resv_ptr->resv_watts == NO_VAL || + resv_ptr->resv_watts == 0) + continue; /* not a power reservation */ + if ((resv_ptr->start_time >= job_end_time) || + (resv_ptr->end_time <= job_start_time)) + continue; /* reservation at different time */ + + if (job_ptr->resv_name && + (strcmp(job_ptr->resv_name, resv_ptr->name) == 0)) + continue; /* job can use this reservation */ + + _update_constraint_planning(&wsched, resv_ptr->resv_watts, + resv_ptr->start_time, + resv_ptr->end_time); + } + list_iterator_destroy(iter); + + resv_cnt = _max_constraint_planning(&wsched, &start, &end); + if (slurm_get_debug_flags() & DEBUG_FLAG_RESERVATION) { + _print_constraint_planning(&wsched); + slurm_make_time_str(&start, start_str, sizeof(start_str)); + slurm_make_time_str(&end, end_str, sizeof(end_str)); + debug2("reservation: max reserved watts=%u (%s to %s)", + resv_cnt, start_str, end_str); + } + _free_constraint_planning(&wsched); + + return resv_cnt; +} + /* * Determine which nodes a job can use based upon reservations * IN job_ptr - job to test diff --git a/src/slurmctld/reservation.h b/src/slurmctld/reservation.h index 2685e210e8bdbf9c0a5c5b30a41eda6173abec29..1af4f9db5c9ff167ba114a81ef66590b3ccf9305 100644 --- a/src/slurmctld/reservation.h +++ b/src/slurmctld/reservation.h @@ -136,6 +136,22 @@ extern burst_buffer_info_msg_t *job_test_bb_resv(struct job_record *job_ptr, extern int job_test_lic_resv(struct job_record *job_ptr, char *lic_name, time_t when); +/* + * Determine how many watts the specified job is prevented from using + * due to reservations + * + * TODO: this code, replicated from job_test_lic_resv seems to not being + * protected against consecutives reservations for which reserved watts + * (or licenses count) can not be added directly. Thus, if the job + * overlaps multiple non-overlapping reservations, it will be prevented + * to use more watts (or licenses) than necessary. + * + * IN job_ptr - job to test + * IN when - when the job is expected to start + * RET amount of watts the job is prevented from using + */ +extern uint32_t job_test_watts_resv(struct job_record *job_ptr, time_t when); + /* * Determine which nodes a job can use based upon reservations * diff --git a/src/slurmctld/slurmctld.h b/src/slurmctld/slurmctld.h index 2114191fb7e0a6f3cb3adb99ebf9a6a5a9b80187..6f925341752b0283ce4c50e1c84c36d5592e8ded 100644 --- a/src/slurmctld/slurmctld.h +++ b/src/slurmctld/slurmctld.h @@ -397,6 +397,7 @@ typedef struct slurmctld_resv { char *partition; /* name of partition to be used */ struct part_record *part_ptr; /* pointer to partition used */ uint32_t resv_id; /* unique reservation ID, internal use */ + uint32_t resv_watts; /* amount of power to reserve */ bool run_epilog; /* set if epilog has been executed */ bool run_prolog; /* set if prolog has been executed */ time_t start_time; /* start time of reservation */ diff --git a/src/sview/resv_info.c b/src/sview/resv_info.c index d4f5d0bc69bc6d20ff23c08c31e7cf7c399f031e..2f9005be907ef8f6cfbdaba4ae1c7ec966167f06 100644 --- a/src/sview/resv_info.c +++ b/src/sview/resv_info.c @@ -71,6 +71,7 @@ enum { SORTID_TIME_START, SORTID_UPDATED, SORTID_USERS, + SORTID_WATTS, SORTID_CNT }; @@ -79,9 +80,9 @@ enum { * known options) create it in function create_model_*. */ -/*these are the settings to apply for the user +/* these are the settings to apply for the user * on the first startup after a fresh slurm install. - * s/b a const probably*/ + * s/b a const probably */ static char *_initial_page_opts = "Name,Node_Count,Core_Count,NodeList," "Time_Start,Time_End"; @@ -141,6 +142,8 @@ static display_data_t display_data_resv[] = { refresh_resv, create_model_resv, admin_edit_resv}, {G_TYPE_INT, SORTID_UPDATED, NULL, FALSE, EDIT_NONE, refresh_resv, create_model_resv, admin_edit_resv}, + {G_TYPE_STRING, SORTID_WATTS, "Watts", FALSE, EDIT_TEXTBOX, + refresh_resv, create_model_resv, admin_edit_resv}, {G_TYPE_NONE, -1, NULL, FALSE, EDIT_NONE} }; @@ -190,6 +193,8 @@ static display_data_t create_data_resv[] = { refresh_resv, create_model_resv, admin_edit_resv}, {G_TYPE_STRING, SORTID_FLAGS, "Flags", FALSE, EDIT_TEXTBOX, refresh_resv, create_model_resv, admin_edit_resv}, + {G_TYPE_STRING, SORTID_WATTS, "Watts", FALSE, EDIT_TEXTBOX, + refresh_resv, create_model_resv, admin_edit_resv}, {G_TYPE_NONE, -1, NULL, FALSE, EDIT_NONE} }; @@ -248,6 +253,27 @@ end_it: } +static uint32_t _parse_watts(char * watts_str) +{ + uint32_t watts_num = 0; + char *end_ptr = NULL; + + if (!strcasecmp(watts_str, "n/a") || !strcasecmp(watts_str, "none")) + return watts_num; + if (!strcasecmp(watts_str, "INFINITE")) + return INFINITE; + watts_num = strtol(watts_str, &end_ptr, 10); + if ((end_ptr[0] == 'k') || (end_ptr[0] == 'K')) { + watts_num *= 1000; + } else if ((end_ptr[0] == 'm') || (end_ptr[0] == 'M')) { + watts_num *= 1000000; + } else if (end_ptr[0] != '\0') { + g_printerr("invalid watts value\n"); + watts_num = NO_VAL; + } + return watts_num; +} + /* don't free this char */ static const char *_set_resv_msg(resv_desc_msg_t *resv_msg, const char *new_text, @@ -349,6 +375,10 @@ static const char *_set_resv_msg(resv_desc_msg_t *resv_msg, resv_msg->users = xstrdup(new_text); type = "users"; break; + case SORTID_WATTS: + resv_msg->resv_watts = _parse_watts((char *) new_text); + type = "watts"; + break; default: type = "unknown"; break; @@ -457,7 +487,7 @@ static GtkWidget *_admin_full_edit_resv(resv_desc_msg_t *resv_msg, gtk_table_set_homogeneous(table, FALSE); - for(i = 0; i < SORTID_CNT; i++) { + for (i = 0; i < SORTID_CNT; i++) { while (display_data++) { if (display_data->id == -1) break; @@ -485,7 +515,7 @@ static void _layout_resv_record(GtkTreeView *treeview, int update) { GtkTreeIter iter; - char time_buf[20]; + char time_buf[20], power_buf[20]; reserve_info_t *resv_ptr = sview_resv_info->resv_ptr; char *temp_char = NULL; @@ -568,13 +598,30 @@ static void _layout_resv_record(GtkTreeView *treeview, find_col_name(display_data_resv, SORTID_USERS), resv_ptr->users); + + if ((resv_ptr->resv_watts == NO_VAL) || (resv_ptr->resv_watts == 0)) { + snprintf(power_buf, sizeof(power_buf), "0"); + } else if ((resv_ptr->resv_watts % 1000000) == 0) { + snprintf(power_buf, sizeof(power_buf), "%uM", + resv_ptr->resv_watts / 1000000); + } else if ((resv_ptr->resv_watts % 1000) == 0) { + snprintf(power_buf, sizeof(power_buf), "%uK", + resv_ptr->resv_watts / 1000); + } else { + snprintf(power_buf, sizeof(power_buf), "%u", + resv_ptr->resv_watts); + } + add_display_treestore_line(update, treestore, &iter, + find_col_name(display_data_resv, + SORTID_WATTS), + power_buf); } static void _update_resv_record(sview_resv_info_t *sview_resv_info_ptr, GtkTreeStore *treestore) { - char tmp_duration[40], tmp_end[40], tmp_nodes[40], tmp_start[40], - tmp_cores[40]; + char tmp_duration[40], tmp_end[40], tmp_nodes[40], tmp_start[40]; + char tmp_cores[40], power_buf[40]; char *tmp_flags; reserve_info_t *resv_ptr = sview_resv_info_ptr->resv_ptr; @@ -596,6 +643,19 @@ static void _update_resv_record(sview_resv_info_t *sview_resv_info_ptr, slurm_make_time_str((time_t *)&resv_ptr->start_time, tmp_start, sizeof(tmp_start)); + if ((resv_ptr->resv_watts == NO_VAL) || (resv_ptr->resv_watts == 0)) { + snprintf(power_buf, sizeof(power_buf), "0"); + } else if ((resv_ptr->resv_watts % 1000000) == 0) { + snprintf(power_buf, sizeof(power_buf), "%uM", + resv_ptr->resv_watts / 1000000); + } else if ((resv_ptr->resv_watts % 1000) == 0) { + snprintf(power_buf, sizeof(power_buf), "%uK", + resv_ptr->resv_watts / 1000); + } else { + snprintf(power_buf, sizeof(power_buf), "%u", + resv_ptr->resv_watts); + } + /* Combining these records provides a slight performance improvement */ gtk_tree_store_set(treestore, &sview_resv_info_ptr->iter_ptr, SORTID_ACCOUNTS, resv_ptr->accounts, @@ -617,6 +677,7 @@ static void _update_resv_record(sview_resv_info_t *sview_resv_info_ptr, SORTID_TIME_END, tmp_end, SORTID_UPDATED, 1, SORTID_USERS, resv_ptr->users, + SORTID_WATTS, power_buf, -1); xfree(tmp_flags);