File indexing completed on 2026-04-10 08:39:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 import os
0011 import re
0012 import logging
0013
0014 from pilot.info import infosys
0015 from pilot.util.disk import disk_usage
0016
0017 logger = logging.getLogger(__name__)
0018
0019
0020 def get_local_disk_space(path):
0021 """
0022 Return remaning disk space for the disk in the given path.
0023 Unit is MB.
0024
0025 :param path: path to disk (string). Can be None, if call to collect_workernode_info() doesn't specify it.
0026 :return: disk space (float).
0027 """
0028
0029 if not path:
0030 return None
0031
0032 disk = 0.0
0033
0034 diskpipe = os.popen("df -mP %s" % path)
0035 disks = diskpipe.read()
0036 if not diskpipe.close():
0037 try:
0038 disk = float(disks.splitlines()[1].split()[3])
0039 except ValueError as error:
0040 logger.warning('exception caught while trying to convert disk info: %s', error)
0041
0042 return disk
0043
0044
0045 def get_meminfo():
0046 """
0047 Return the total memory (in MB).
0048
0049 :return: memory (float).
0050 """
0051
0052 mem = 0.0
0053 with open("/proc/meminfo", "r") as fd:
0054 mems = fd.readline()
0055 while mems:
0056 if mems.upper().find("MEMTOTAL") != -1:
0057 try:
0058 mem = float(mems.split()[1]) / 1024
0059 except ValueError as error:
0060 logger.warning('exception caught while trying to convert meminfo: %s', error)
0061 break
0062 mems = fd.readline()
0063
0064 return mem
0065
0066
0067 def get_cpuinfo():
0068 """
0069 Return the CPU frequency (in MHz).
0070
0071 :return: cpu (float).
0072 """
0073
0074 cpu = 0.0
0075 with open("/proc/cpuinfo", "r") as fd:
0076 lines = fd.readlines()
0077 for line in lines:
0078 if line.find("cpu MHz") != -1:
0079 try:
0080 cpu = float(line.split(":")[1])
0081 except ValueError as error:
0082 logger.warning('exception caught while trying to convert cpuinfo: %s', error)
0083 break
0084
0085 return cpu
0086
0087
0088 def collect_workernode_info(path=None):
0089 """
0090 Collect node information (cpu, memory and disk space).
0091 The disk space (in MB) is return for the disk in the given path.
0092
0093 :param path: path to disk (string).
0094 :return: memory (float), cpu (float), disk space (float).
0095 """
0096
0097 mem = get_meminfo()
0098 cpu = get_cpuinfo()
0099 disk = get_local_disk_space(path)
0100
0101 return mem, cpu, disk
0102
0103
0104 def get_disk_space(queuedata):
0105 """
0106 Get the disk space from the queuedata that should be available for running the job;
0107 either what is actually locally available or the allowed size determined by the site (value from queuedata). This
0108 value is only to be used internally by the job dispatcher.
0109
0110 :param queuedata: infosys object.
0111 :return: disk space that should be available for running the job (int).
0112 """
0113
0114
0115
0116 _maxinputsize = infosys.queuedata.maxwdir
0117 logger.debug("resolved value from global infosys.queuedata instance: infosys.queuedata.maxwdir=%s B", _maxinputsize)
0118 _maxinputsize = queuedata.maxwdir
0119 logger.debug("resolved value: queuedata.maxwdir=%s B", _maxinputsize)
0120
0121 try:
0122 du = disk_usage(os.path.abspath("."))
0123 _diskspace = int(du[2] / (1024 * 1024))
0124 except ValueError as error:
0125 logger.warning("failed to extract disk space: %s (will use schedconfig default)", error)
0126 _diskspace = _maxinputsize
0127 else:
0128 logger.info("available WN disk space: %d MB", _diskspace)
0129
0130 _diskspace = min(_diskspace, _maxinputsize)
0131 logger.info("sending disk space %d MB to dispatcher", _diskspace)
0132
0133 return _diskspace
0134
0135
0136 def get_node_name():
0137 """
0138 Return the local node name.
0139
0140 :return: node name (string)
0141 """
0142 if 'PANDA_HOSTNAME' in os.environ:
0143 host = os.environ.get('PANDA_HOSTNAME')
0144 elif hasattr(os, 'uname'):
0145 host = os.uname()[1]
0146 else:
0147 import socket
0148 host = socket.gethostname()
0149
0150 return get_condor_node_name(host)
0151
0152
0153 def get_condor_node_name(nodename):
0154 """
0155 On a condor system, add the SlotID to the nodename
0156
0157 :param nodename:
0158 :return:
0159 """
0160
0161 if "_CONDOR_SLOT" in os.environ:
0162 nodename = "%s@%s" % (os.environ.get("_CONDOR_SLOT"), nodename)
0163
0164 return nodename
0165
0166
0167 def get_cpu_model():
0168 """
0169 Get cpu model and cache size from /proc/cpuinfo.
0170
0171 Example.
0172 model name : Intel(R) Xeon(TM) CPU 2.40GHz
0173 cache size : 512 KB
0174
0175 gives the return string "Intel(R) Xeon(TM) CPU 2.40GHz 512 KB".
0176
0177 :return: cpu model (string).
0178 """
0179
0180 cpumodel = ""
0181 cpucache = ""
0182 modelstring = ""
0183
0184 re_model = re.compile(r'^model name\s+:\s+(\w.+)')
0185 re_cache = re.compile(r'^cache size\s+:\s+(\d+ KB)')
0186
0187 with open("/proc/cpuinfo", "r") as f:
0188
0189
0190 for line in f.readlines():
0191
0192 model = re_model.search(line)
0193 if model:
0194
0195 cpumodel = model.group(1)
0196
0197
0198 cache = re_cache.search(line)
0199 if cache:
0200
0201 cpucache = cache.group(1)
0202
0203
0204 if cpumodel and cpucache:
0205
0206 modelstring = cpumodel + " " + cpucache
0207 break
0208
0209
0210 if not modelstring:
0211 modelstring = "UNKNOWN"
0212
0213 return modelstring
0214
0215
0216 def check_hz():
0217 """
0218 Try to read the SC_CLK_TCK and write it to the log.
0219
0220 :return:
0221 """
0222
0223 try:
0224 _ = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
0225 except Exception:
0226 import traceback
0227 logger.fatal('failed to read SC_CLK_TCK - will not be able to perform CPU consumption calculation')
0228 logger.warning(traceback.format_exc())