Skip to content

Commit 1375f7b

Browse files
committed
Use psutil library to update process stats instead of ps command
Signed-off-by: MuLin <[email protected]>
1 parent 13353df commit 1375f7b

File tree

3 files changed

+54
-27
lines changed

3 files changed

+54
-27
lines changed

sonic-slave-bullseye/Dockerfile.j2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ RUN pip3 install pytest-runner==5.2
423423
RUN pip3 install nose==1.3.7
424424
RUN pip3 install mockredispy==2.9.3
425425

426+
# For procdockerstatsd_test.py
427+
RUN pip3 install psutil==5.9.0
428+
426429
# For p4 build
427430
RUN pip3 install \
428431
ctypesgen==1.0.2 \

sonic-slave-buster/Dockerfile.j2

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ RUN pip3 install nose==1.3.7
444444
RUN pip2 install mockredispy==2.9.3
445445
RUN pip3 install mockredispy==2.9.3
446446
447+
# For procdockerstatsd_test.py
448+
RUN pip3 install psutil==5.9.0
449+
447450
# For Python 2 unit tests, we need 'mock'. The last version of 'mock'
448451
# which supports Python 2 is 3.0.5. In Python 3, 'mock' is part of 'unittest'
449452
# in the standard library
@@ -513,7 +516,7 @@ EXPOSE 22
513516
RUN git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /usr/share/depot_tools
514517
ENV PATH /usr/share/depot_tools:$PATH
515518
516-
# Install dependencies for dhcp relay test
519+
# Install dependencies for dhcp relay test
517520
RUN pip3 install parameterized==0.8.1
518521
RUN pip3 install pyfakefs
519522

src/sonic-host-services/scripts/procdockerstatsd

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import re
99
import subprocess
1010
import sys
1111
import time
12+
import psutil
1213
from datetime import datetime
1314

1415
from sonic_py_common import daemon_base
@@ -129,40 +130,60 @@ class ProcDockerStats(daemon_base.DaemonBase):
129130
return False
130131
# wipe out all data from state_db before updating
131132
self.state_db.delete_all_by_pattern('STATE_DB', 'DOCKER_STATS|*')
132-
for k1,v1 in dockerdata.items():
133-
for k2,v2 in v1.items():
133+
for k1, v1 in dockerdata.items():
134+
for k2, v2 in v1.items():
134135
self.update_state_db(k1, k2, v2)
135136
return True
136137

138+
def get_proc_data(self, proc):
139+
result = {}
140+
result['UID'] = proc.uids().real
141+
result['PPID'] = proc.ppid()
142+
result['%CPU'] = round(proc.cpu_percent(), 1)
143+
result['%MEM'] = round(proc.memory_percent(), 1)
144+
result['CREATE_TIME'] = proc.create_time() # seconds
145+
stime = datetime.fromtimestamp(proc.create_time())
146+
uptime = time.time() - proc.create_time()
147+
stime_str = stime.strftime("%b%d") if uptime > (24 * 60 * 60) else stime.strftime("%H:%M")
148+
result['STIME'] = stime_str # Mmmdd or HH:MM
149+
result['ELAPSED'] = round(uptime, 2) # seconds
150+
tty = proc.terminal()
151+
result['TT'] = tty.lstrip('/dev/') if tty else "?"
152+
result['TIME'] = self.get_time_str(int(sum(proc.cpu_times()[:2]))) # [DD-]hh:mm:ss
153+
result['CPU_TIME_USER'] = proc.cpu_times().user
154+
result['CPU_TIME_SYSTEM'] = proc.cpu_times().system
155+
result['MEMORY_USAGE'] = proc.memory_info().rss # bytes
156+
result['CMD'] = " ".join(proc.cmdline()).strip(" \n")
157+
158+
result = {key: str(result[key]) for key in result}
159+
return result
160+
137161
def update_processstats_command(self):
138-
data = self.run_command("ps -eo uid,pid,ppid,%mem,%cpu,stime,tty,time,cmd --sort -%cpu | head -1024")
139-
processdata = self.format_process_cmd_output(data)
140-
value = ""
141162
# wipe out all data before updating with new values
142163
self.state_db.delete_all_by_pattern('STATE_DB', 'PROCESS_STATS|*')
143-
for row in processdata[0:]:
144-
cid = row.get('PID')
145-
if cid:
146-
value = 'PROCESS_STATS|{}'.format(cid)
147-
uid = row.get('UID')
148-
self.update_state_db(value, 'UID', uid)
149-
ppid = row.get('PPID')
150-
self.update_state_db(value, 'PPID', ppid)
151-
cpu = row.get('%CPU')
152-
self.update_state_db(value, '%CPU', str(cpu))
153-
mem = row.get('%MEM')
154-
self.update_state_db(value, '%MEM', str(mem))
155-
stime = row.get('STIME')
156-
self.update_state_db(value, 'STIME', stime)
157-
tty = row.get('TT')
158-
self.update_state_db(value, 'TT', tty)
159-
time = row.get('TIME')
160-
self.update_state_db(value, 'TIME', time)
161-
cmd = row.get('CMD')
162-
self.update_state_db(value, 'CMD', cmd)
164+
for proc in psutil.process_iter():
165+
key = 'PROCESS_STATS|{}'.format(proc.pid)
166+
field_value = self.get_proc_data(proc)
167+
self.update_state_db_all(key,field_value)
168+
169+
def get_time_str(self, time_second):
170+
days = int(time_second / (24 * 60 * 60))
171+
hours = int((time_second % (24 * 60 * 60)) / (60 * 60))
172+
minutes = int((time_second % (60 * 60)) / 60)
173+
seconds = int(time_second % 60)
174+
result = "{}{}{}{}".format(
175+
str(days).zfill(2) + "-" if days > 0 else "",
176+
str(hours).zfill(2) + ":",
177+
str(minutes).zfill(2) + ":",
178+
str(seconds).zfill(2)
179+
)
180+
return result
163181

164182
def update_state_db(self, key1, key2, value2):
165-
self.state_db.set('STATE_DB', key1, key2, value2)
183+
self.state_db.set('STATE_DB', key1, key2, str(value2))
184+
185+
def update_state_db_all(self, key1, dict1):
186+
self.state_db.hmset('STATE_DB', key1, dict1)
166187

167188
def run(self):
168189
self.log_info("Starting up ...")

0 commit comments

Comments
 (0)