This is an old revision of the document!
Table of Contents
Accounting Troubleshooting
Luego de la actualización de Lenovo, nuestro mecanismo para informar a usuarios sobre su consumo de horas se vió afectado, ya que el mismo dependía del comando scontrol show assoc_mgr.
[bbruzzo@snmgt01 ~]$ scontrol show assoc_mgr | grep -A 7 "QOS=qos_pisca_145("
QOS=qos_pisca_145(122)
UsageRaw=0.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(0.00)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=6000000(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=60000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
MaxWallPJ=
MaxTRESPJ=
Revisión de Database
Para hacer un dump de la database, desde mmgt02:
sudo mysqldump --single-transaction --databases slurm_acct_db > backup.sql
Parsear desde sacct
sacct -X -a -A pisca_73 --starttime=2025-01-01 --parsable2 --noheader --format=elapsedraw,ncpus | awk -F'|' '{sum+=$1*$2} END {print sum/3600}'
Python Script reporte horas
#!/usr/bin/env python3.10
import subprocess
def get_accounts():
command = ['sacctmgr', '--noheader', 'list', 'account', 'format=account']
output = subprocess.run(command,capture_output=True,encoding='utf-8')
accounts = output.stdout.split()
return accounts
def get_hours(account):
command = ['sacct', '-X', '-a', '-A', str(account), '--starttime=2025-01-01', '--parsable2', '--noheader', '--format=elapsedraw,ncpus']
pipe_command= ['awk', '-F|', '{sum+=$1*$2} END {print sum/3600}']
proc = subprocess.Popen(command,stdout=subprocess.PIPE)
pipe_proc = subprocess.Popen(pipe_command,stdin=proc.stdout,stdout=subprocess.PIPE,encoding='utf-8')
stdout,stderr = pipe_proc.communicate()
print(account)
print(stdout)
if __name__ == '__main__':file> syntax as above, you might want to make the shown code available for download as well. You can
accounts = get_accounts()
for account in accounts:
if account.startswith(('pad','pci','pisca')):
get_hours(account)
Explorando con una QOS de prueba
Quiero corroborar que a pesar de que assoc_mgr ya no reporte horas de qos, no ocurra que las qos igual tengan sus recursos usados registrados, ya que los mismos figuran via sacct y via la db.
Tenemos la qosprueba.
$ sacctmgr list qos qos=qosprueba format=name,flags,grptresmins%30
Name Flags GrpTRESMins
---------- -------------------- ------------------------------
qosprueba DenyOnLimit,NoDecay cpu=3000,gres/gpu=2000
La misma figura con 1100 minutos CPU.
$ sacct -X -a -q qosprueba --starttime=2025-01-01 --parsable2 --noheader --format=elapsedraw,ncpus | awk -F'|' '{sum+=$1*$2} END {print sum/60}'
1100.68
Son jobs que se utilizaron con los usuarios 'prueba' y 'utest' con la cuenta 'cuentaprueba'.
$ sacct -X -a -q qosprueba --starttime=2025-01-01 --format=jobid,submit,jobname,user,account,partition,qos,elapsedraw,ncpus JobID Submit JobName User Account Partition QOS ElapsedRaw NCPUS ------------ ------------------- ---------- --------- ---------- ---------- ---------- ---------- ---------- 604 2025-06-18T15:47:10 lammps-gpu prueba cuentapru+ gpunode qosprueba 9 1 605 2025-06-18T15:47:32 lammps-gpu prueba cuentapru+ gpunode qosprueba 625 1 609 2025-06-18T15:59:17 lammps-gpu prueba cuentapru+ gpunode qosprueba 1 1 610 2025-06-18T16:06:43 lammps-gpu prueba cuentapru+ gpunode qosprueba 1394 1 624 2025-06-19T15:56:24 Sleep prueba cuentapru+ gpunode qosprueba 61 64 626 2025-06-19T16:19:01 lammps-gpu prueba cuentapru+ gpunode qosprueba 604 1 628 2025-06-19T16:32:34 lammps-gpu prueba cuentapru+ gpunode qosprueba 25 1 629 2025-06-19T16:34:39 lammps-gpu prueba cuentapru+ gpunode qosprueba 28 1 630 2025-06-19T16:50:13 Sleep prueba cuentapru+ gpunode qosprueba 11 64 631 2025-06-19T16:51:05 lammps-gpu prueba cuentapru+ gpunode qosprueba 29 1 632 2025-06-19T16:53:00 lammps-gpu prueba cuentapru+ gpunode qosprueba 26 1 633 2025-06-19T16:55:24 xpu prueba cuentapru+ gpunode qosprueba 2 64 637 2025-06-23T15:00:07 Sleep prueba cuentapru+ gpunode qosprueba 61 64 638 2025-06-23T15:13:08 Sleep prueba cuentapru+ gpunode qosprueba 0 0 639 2025-06-23T15:13:22 Sleep prueba cuentapru+ gpunode qosprueba 39 64 640 2025-06-23T15:15:20 Sleep prueba cuentapru+ gpunode qosprueba 60 64 970 2025-07-07T18:00:08 Sleep prueba cuentapru+ gpunode qosprueba 61 64 971 2025-07-07T18:08:10 Sleep prueba cuentapru+ gpunode qosprueba 0 0 972 2025-07-07T18:10:27 Sleep prueba cuentapru+ gpunode qosprueba 61 64 973 2025-07-07T18:15:28 Sleep prueba cuentapru+ gpunode qosprueba 61 64 974 2025-07-07T18:16:51 Sleep prueba cuentapru+ gpunode qosprueba 61 64 975 2025-07-07T18:20:12 Sleep prueba cuentapru+ gpunode qosprueba 61 64 983 2025-07-08T13:27:36 Sleep prueba cuentapru+ gpunode qosprueba 61 64 984 2025-07-08T13:30:06 Sleep prueba cuentapru+ gpunode qosprueba 61 64 985 2025-07-08T13:31:36 Sleep prueba cuentapru+ gpunode qosprueba 61 64 986 2025-07-08T13:32:45 Sleep prueba cuentapru+ gpunode qosprueba 0 0 987 2025-07-08T13:35:16 Sleep prueba cuentapru+ gpunode qosprueba 60 64 988 2025-07-08T13:38:29 Sleep prueba cuentapru+ gpunode qosprueba 60 64 1083 2025-07-18T16:40:49 bash utest cuentapru+ gpunode qosprueba 65 64 1084 2025-07-18T16:53:39 bash utest cuentapru+ gpunode qosprueba 30 64 1085 2025-07-18T16:54:53 bash utest cuentapru+ gpunode qosprueba 61 1 1086 2025-07-18T16:59:05 bash utest cuentapru+ gpunode qosprueba 79 1 1088 2025-07-18T17:03:20 bash utest cuentapru+ gpunode qosprueba 65 1 1090 2025-07-18T17:07:26 bash utest cuentapru+ gpunode qosprueba 53 1 1091 2025-07-18T17:09:10 bash utest cuentapru+ gpunode qosprueba 75 1 1092 2025-07-18T17:11:29 bash utest cuentapru+ gpunode qosprueba 55 1 1093 2025-07-18T17:12:58 bash utest cuentapru+ gpunode qosprueba 40 64 1139 2025-07-21T14:39:42 slurm.job utest cuentapru+ gpunode qosprueba 1 64 1141 2025-07-21T14:44:54 slurm.job utest cuentapru+ gpunode qosprueba 1 64 1158 2025-07-21T15:57:15 slurm.job utest cuentapru+ gpunode qosprueba 1 64 1159 2025-07-21T16:01:58 slurm.job utest cuentapru+ gpunode qosprueba 1 64 1167 2025-07-21T16:38:06 slurm.job utest cuentapru+ gpunode qosprueba 1 64 1168 2025-07-21T16:43:35 slurm.job utest cuentapru+ gpunode qosprueba 1 64
La cuenta 'cuentaprueba' fue eliminada y ya no existe:
$ sacctmgr list account account=cuentaprueba Account Descr Org ---------- -------------------- --------------------
Pero podemos asociar la qos a otra account para probarla.
Antes de hacer nada verificamos que la qos reporta 0 horas de uso con assoc_mgr.
$ scontrol show assoc_mgr | grep -A 7 "QOS=qosprueba("
QOS=qosprueba(32)
UsageRaw=0.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(0.00)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=3000(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=2000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
MaxWallPJ=
MaxTRESPJ=
Lo mismo podemos ver con scontrol show assoc.
$ scontrol show assoc | grep qosprueba -A 10
QOS=qosprueba(32)
UsageRaw=0.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(0.00)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=3000(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=2000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
MaxWallPJ=
MaxTRESPJ=
MaxTRESPN=
MaxTRESMinsPJ=
MinPrioThresh=
Como vemos, indica:
GrpTRESMins=cpu=3000(0) ... gres/gpu=2000(0)
En efecto, pareceria que hay 3000 minutos disponibles, cuando ya fueron utilizados 1100. Queremos comprobar si hay 3000 minutos disponibles, o solamente 1900.
Asignamos la qos a una cuenta de root.
# sacctmgr show assoc user=root WithRawQOSLevel format=cluster,account,user,defaultqos,grptresmins,qos,qosraw Cluster Account User Def QOS GrpTRESMins QOS QOS_RAW ---------- ---------- ---------- --------- ------------- -------------------- ---------- clementina root root normal 1 $ sacctmgr modify user root set qos+=qosprueba Modified user associations... C = clementina A = root U = root Would you like to commit changes? (You have 30 seconds to decide) (N/y): y $ sacctmgr show assoc user=root WithRawQOSLevel format=cluster,account,user,defaultqos,grptresmins,qos,qosraw Cluster Account User Def QOS GrpTRESMins QOS QOS_RAW ---------- ---------- ---------- --------- ------------- -------------------- ---------- clementina root root normal,qosprueba 1,32
Enviemos un job de 2000 minutos a ver que ocurre.
#!/bin/bash #SBATCH --job-name=sleep #SBATCH --ntasks=12 #SBATCH --partition=gpunode #SBATCH --qos=qosprueba #SBATCH --time=200 #200 minutos en 12 cores son 2400 minutos. sleep 60000 # el job debería hacer timeout por la directiva --time.
A priori me permitió encolar el job:
[root@mmgt02 slurm]# sbatch sleep.sh
Submitted batch job 281155
[root@mmgt02 slurm]# squeue --me
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
281155 gpunode sleep root PD 0:00 1 (Priority)
El job muestra como qos asignada qosprueba.
[root@mmgt02 slurm]# scontrol show job 281155 JobId=281155 JobName=sleep UserId=root(0) GroupId=root(0) MCS_label=N/A Priority=6 Nice=0 Account=root QOS=qosprueba JobState=RUNNING Reason=None Dependency=(null) Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:0 RunTime=00:02:03 TimeLimit=03:20:00 TimeMin=N/A SubmitTime=2026-02-04T11:10:55 EligibleTime=2026-02-04T11:10:55 AccrueTime=2026-02-04T11:10:55 StartTime=2026-02-04T11:11:06 EndTime=2026-02-04T14:31:06 Deadline=N/A SuspendTime=None SecsPreSuspend=0 LastSchedEval=2026-02-04T11:11:06 Scheduler=Backfill Partition=gpunode AllocNode:Sid=mmgt02:3468048 ReqNodeList=(null) ExcNodeList=(null) NodeList=cn067 BatchHost=cn067 NumNodes=1 NumCPUs=12 NumTasks=12 CPUs/Task=1 ReqB:S:C:T=0:0:*:* ReqTRES=cpu=12,mem=768G,node=1,billing=12 AllocTRES=cpu=12,node=1,billing=12 Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=* MinCPUsNode=1 MinMemoryCPU=64G MinTmpDiskNode=0 Features=(null) DelayBoot=00:00:00 OverSubscribe=OK Contiguous=0 Licenses=(null) Network=(null) Command=/home/bbruzzo/slurm/sleep.sh WorkDir=/home/bbruzzo/slurm StdErr=/home/bbruzzo/slurm/slurm-281155.out StdIn=/dev/null StdOut=/home/bbruzzo/slurm/slurm-281155.out Power=
El job terminó de correr, osea usó más tiempo del que podía:
[root@mmgt02 admin]# sacct -Xu root --format=jobid,jobname,partition,account,state,exitcode,elapsedraw,ncpus JobID JobName Partition Account State ExitCode ElapsedRaw NCPUS ------------ ---------- ---------- ---------- ---------- -------- ---------- ---------- 281155 sleep gpunode root TIMEOUT 0:0 12024 12
[root@mmgt02 admin]# scontrol show assoc_mgr | grep "QOS=qosprueba" -A 21
QOS=qosprueba(32)
UsageRaw=144288.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(200.40)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=3000(2404),mem=N(0),energy=N(0),node=N(200),billing=N(2404),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=2000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
MaxWallPJ=
MaxTRESPJ=
MaxTRESPN=
MaxTRESMinsPJ=
MinPrioThresh=
MinTRESPJ=
PreemptMode=OFF
Priority=0
Account Limits
root
MaxJobsPA=N(0) MaxJobsAccruePA=N(0) MaxSubmitJobsPA=N(0)
MaxTRESPA=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
User Limits
root(0)
MaxJobsPU=N(0) MaxJobsAccruePU=N(0) MaxSubmitJobsPU=N(0)
MaxTRESPU=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
Ahora muestra que la qos tiene 3000 horas disponibles pero usó 3500.
sacct -X -a -q qosprueba --starttime=2025-01-01 --parsable2 --noheader --format=elapsedraw,ncpus | awk -F'|' '{sum+=$1*$2} END {print sum/60}'
3505.48
UsageRaw=144288.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(200.40)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=3000(2404),mem=N(0),energy=N(0),node=N(200),billing=N(2404),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=2000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
¿Vuelve a entrar el mismo job?
Si, vuelve a correr:
[root@mmgt02 ~]# sacct -X -a -q qosprueba --starttime=2026-02-04 --format=JobID,JobName,Account,QOS,AllocCPUS,State,Elapsed JobID JobName Account QOS AllocCPUS State Elapsed ------------ ---------- ---------- ---------- ---------- ---------- ---------- 281155 sleep root qosprueba 12 TIMEOUT 03:20:24 282169 sleep root qosprueba 12 TIMEOUT 00:52:59
[root@mmgt02 ~]# sacct -X -a -q qosprueba --starttime=2025-01-01 --parsable2 --noheader --format=elapsedraw,ncpus | awk -F'|' '{sum+=$1*$2} END {print sum/60}'
4141.28
Vemos que la qos tiene consumidos 4141 minutos.
Cree que corrió 3040 minutos:
# scontrol show assoc_mgr | grep -A 7 "QOS=qosprueba("
QOS=qosprueba(32)
UsageRaw=182436.000000
GrpJobs=N(0) GrpJobsAccrue=N(0) GrpSubmitJobs=N(0) GrpWall=N(253.38)
GrpTRES=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESMins=cpu=3000(3040),mem=N(0),energy=N(0),node=N(253),billing=N(3040),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=2000(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
GrpTRESRunMins=cpu=N(0),mem=N(0),energy=N(0),node=N(0),billing=N(0),fs/disk=N(0),vmem=N(0),pages=N(0),gres/gpu=N(0),gres/gpu:v100=N(0),gres/gpumem=N(0),gres/gpuutil=N(0)
MaxWallPJ=
MaxTRESPJ=
DefaultQOS
Previo al update las accounts tenían una QOS por default (o no?).
Hay que actualizarlo para que contabilice las horas correctamente:
$ sacctmgr modify account set defaultqos=qos_pisca_73 where account=pisca_73
To be continued...
Utilicé este script para actualizar las qos a los valores restantes y setear las qos default:
- fix_qos.py
#!/usr/bin/env python3.10 import subprocess def get_accounts(): command = ['sacctmgr', '--noheader', 'list', 'account', 'format=account'] output = subprocess.run(command,capture_output=True,encoding='utf-8') accounts = output.stdout.split() return accounts def get_hours(account): command = ['sacct', '-X', '-a', '-A', str(account), '--starttime=2025-01-01', '--parsable2', '--noheader', '--format=elapsedraw,ncpus'] cpu_hours_command = ['sreport', 'cluster', 'userutilizationbyaccount', '--noheader', '--parsable2', '--tres=cpu', 'accounts='+str(account), 'format=used', 'start=2025-05-01T00:00:00'] gpu_hours_command = ['sreport', 'cluster', 'userutilizationbyaccount', '--noheader', '--parsable2', '--tres=gres/gpu', 'accounts='+str(account), 'format=used', 'start=2025-05-01T00:00:00'] cpu_hours = subprocess.run( cpu_hours_command, capture_output=True, encoding='utf-8').stdout.split() cpu_hours = [int(i) for i in cpu_hours] cpu_hours = sum(cpu_hours) gpu_hours = subprocess.run( gpu_hours_command, capture_output=True, encoding='utf-8').stdout.split() gpu_hours = [int(i) for i in gpu_hours] gpu_hours = sum(gpu_hours) return cpu_hours, gpu_hours def update_qos(account): match account: case a if a.startswith('pad'): default_cpu, default_gpu = 240000000,15000000 case a if a.startswith('pci'): default_cpu, default_gpu = 60000000,3600000 case a if a.startswith('pisca'): default_cpu, default_gpu = 6000000,60000 spent_cpu, spent_gpu = get_hours(account) new_cpu = max(0,default_cpu-spent_cpu) new_gpu = max(0,default_gpu-spent_gpu) update_command = ['sacctmgr', 'modify', 'qos', 'qos_'+str(account), 'set', 'GrpTRESMins=cpu='+str(new_cpu)+',gres/gpu='+str(new_gpu)] print(update_command) subprocess.run(update_command) def update_defqos(account): ''' Sets Default QOS to IPAC project in case of misconfiguration. ''' command = ['sacctmgr', 'modify', 'account', 'set', 'defaultqos=qos_'+str(account), 'where', 'account='+str(account)] subprocess.run(command) def action(accounts,func=get_hours): for account in accounts: if account.startswith(('pad','pci','pisca')): func(account) actions = { '1': get_hours, '2': update_defqos, '3': update_qos, } if __name__ == '__main__': print("Elegir que acción ejecutar en slurm:\n","1) get_hours\n", "2) update_defqos\n","3) update_qos\n") choice = input("Elegir:") func = actions.get(choice) accounts = get_accounts() if func: action(accounts,func) else: print("Operación invalida")
