Given PyQt5 on Linux, I have an application that starts a terminal emulator (rxvt) and runs a command (gaurdian) which runs yet another program (goo). Like this
medi#medi:~> pstree -p 4610
rxvt(4610)─┬─gaurdian(4612)───goo(4613)
└─rxvt(4611)
I am trying to find pid of "goo". So I proceed with
gooPID = 12 # some random value to show my point
self.process.start(cmd, cmdOpts)
rxvtPID = self.process.processId()
try:
for c in psutil.Process(rxvtPID).children(True):
print("pid=%d name=%s" % (c.pid, c.name()))
if c.name() == 'gaurdian':
gooPID = c.pid
except (psutil.ZombieProcess, psutil.AccessDenied, psutil.NoSuchProcess) as err:
print(err)
print("gooPID=%d " % gooPID )
The trace log is showing:
rxvtPID=4610 name=rxvt
gooPID=12
which suggests that the initial value of gooPID was not changed. Also seems like traversal of children is not happening (ie I am not seeing children of children, etc).
Am I doing this right ?
I managed to solve this by inserting a sleep(1) before psutil begins to traverse the /proc filesystem. That is
209 # ----------------------- getPidByName() ----------------------
210 def getPidByName(self, name):
211 rxvtProc = psutil.Process(self.process.processId() )
212 time.sleep(1) # else /proc is not ready for read
213 pid = None
214 try:
215 for c in rxvtProc.children(True):
216 # assumption: gaurdian has only one child
217 if c.name() == name:
218 return psutil.Process(c.pid).children()[0].pid
219 except psutil.Error as err:
220 print(err)
221 return pid
Related
I'm using python3-pexpect 4.8.0-2 from Debian Bullseye to control functions on an embedded device via RS232. This works quite well, however on the two of those functions pexpect sometimes misses an answer. Strangely the logfiles written by pexpect itself (child.logfile) always do contain the missing line. So I suspect an error in my own code.
I use fdspawn() for the serial device:
pexpect.run("stty sane raw cstopb -echo -echoe -echok -echoctl -echoke -iexten 115200 -F /dev/ttyS0")
fd = os.open("/dev/ttyS0", os.O_RDWR|os.O_NONBLOCK|os.O_NOCTTY)
self.child = pexpect.fdpexpect.fdspawn(fd, encoding='utf-8')
self.child.logfile = open("serial.log", "w")
There are 2 methods which fail with a timeout error in 5 to 10% of all runs. I stripped one down to the bare minimum neccessary to understand it.
def command(self, cmd, timeout, what, errmsg):
resp = ["ERROR CRC", "monitor: ERROR", what]
res = ""
try:
self.sendline(cmd)
while True:
idx = self.child.expect_exact(resp, timeout)
if idx == 0:
raise Rs232Error("RS232 error ({})".format(self.child.after))
elif idx != 1:
res = self.child.after # return matched string
break
log.debug("Ignoring ERROR")
pass
except pexpect.exceptions.TIMEOUT as e:
raise TimeoutError(errmsg)
return res
def answer(self, regexp, timeout=2):
l = ["\[[0-9]+\] {}\r\n".format(regexp), "\[[0-9]+\] ERROR.+\r\n"]
try:
idx = self.child.expect(l, timeout)
except pexpect.exceptions.TIMEOUT as e:
raise TimeoutError("No answer (last: {})".format(self.child.before))
s = self.child.after
m = re.match("\[([0-9]+)\] (.+)\r\n", s)
t = m.group(2)
return s
def rs485Test(self, oline, iline):
cmd = "%s %u" %("T 190", oline)
data = ""
self.command("%s %s" %(cmd, data), 5, "Test 190 execution", "Command %s not accepted" %(cmd))
v = self.answer("RS485-%u Tx: .+" %(oline), 5) # Check echo
try:
v = self.answer("RS485-%u Rx: .+" %(iline), 10)
except TimeoutError as e:
return 1, "Receive timed out (%s)" %(str(e)) # testcase failed!
return 0, v
As written above: the missing line is always logged. But pexpect does not return it and the TimeoutError message doesn't contain it either (as in "No answer (last: )"). The echo ("RS485-%u Tx" is sendout within 1 ms and never missed. The received data follows 6-8 ms later and is missing.
How could I debug the issue?
Sorry, I missed an example. The first call (sending via RS485-0 and receiving via RS485-1) was missed by above code. In the second call worked it worked fine. I see no difference.
T 230 0 AB 70 9A C8 3F 44#FC
[8638628] Test 190/230 execution^M
[8638629] RS485-0 Tx: AB 70 9A C8 3F 44 ^M
[8638635] RS485-1 Rx: AB 70 9A C8 3F 44 ^M
T 190 1 60 AC 24 DF 46 AB#09
[8648659] Test 190/230 execution^M
[8648660] RS485-1 Tx: 60 AC 24 DF 46 AB ^M
[8648666] RS485-0 Rx: 60 AC 24 DF 46 AB ^M
I am not sure whether this is an iOS issue or whether this is an issue with Kivy or even with Python (e.g. https://bugs.python.org/issue37788), but I am experiencing some problems with threading.
I have built an iPad app using the Kivy framework that makes several calls to an API, and uses the threading module to asynchronously make requests. Below is the code that handles the API requests:
import json
import requests
import base64
import threading
def thread(function):
def wrap(*args, **kwargs):
t = threading.Thread(target=function, args=args, kwargs=kwargs)
t.start()
return t
return wrap
class MathPixAPI:
stroke_url = '*******************'
header = {
"content-type": "application/json",
"app_id": "*******************",
"app_key": "*******************"
}
#thread
def post_data(self, file_name: str, root):
"""
Posts a base64 encoded image to the MathPixAPI then updates the data DictProperty of the ExpressionWriter that
calls this function
:param file_name: The name of the file - e.g. "image.png"
:param root: The ExpressionWriter that calls the function
"""
image_uri = "data:image/png;base64," + base64.b64encode(open(file_name, "rb").read()).decode()
r = requests.post("https://api.mathpix.com/v3/text",
data=json.dumps({'src': image_uri}),
headers=self.header)
root.data = json.loads(r.text)
The app makes no more than 5 asynchronous requests at one time, and is called from the function below:
def get_image_data(self):
"""
The function first saves the ExpressionWriter.canvas as a PNG file to the user_data_directory (automatically
determined depending on the device the user is running the app on). Then this images is sent to the MathPix API
which then return data on the handwritten answer (see api.py for more details). The api call updates self.data
which in turn calls self._on_data().
"""
file_name = f'{App.get_running_app().user_data_dir}/image_{self.number}.png'
self.export_to_png(file_name)
MathPixAPI().post_data(file_name, self)
This works really well, up until the 20th-25th request, upon which the program halts. In Xcode I receive the following error log:
021-04-09 18:11:02.300179+0100 ccc-writer-3[4261:4790641] [Animation] +[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior. trace=(
0 UIKitCore 0x0000000187cbb538 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17859896
1 libdispatch.dylib 0x0000000101ce56c0 _dispatch_client_callout + 20
2 libdispatch.dylib 0x0000000101ce71f8 _dispatch_once_callout + 136
3 UIKitCore 0x0000000187cbb4bc 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17859772
4 UIKitCore 0x0000000187cbb628 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17860136
5 UIKitCore 0x0000000187abbd64 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 15764836
6 UIKitCore 0x0000000187aae150 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 15708496
7 UIKitCore 0x00000001877b2f20 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 12582688
8 UIKitCore 0x0000000187cb2b30 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17824560
9 UIKitCore 0x0000000187aacd50 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 15703376
10 ccc-writer-3 0x0000000100822960 -[SDL_uikitviewcontroller showKeyboard] + 108
11 ccc-writer-3 0x0000000100823164 UIKit_ShowScreenKeyboard + 60
12 ccc-writer-3 0x00000001007ec490 SDL_StartTextInput + 92
... [A whole bunch of memory addresses] ...
74 ccc-writer-3 0x0000000100610df4 _PyEval_EvalFrameDefault + 5432
75 ccc-writer-3 0x000000010054dfe0 function_code_fastcall + 120
76 ccc-writer-3 0x00000001005505f8 method_vectorcall + 264
77 ccc-writer-3 0x000000010054d95c PyVectorcall_Call + 104
78 ccc-writer-3 0x0000000100770c40 t_bootstrap + 80
79 ccc-writer-3 0x000000010065e8e8 pythread_wrapper + 28
80 libsystem_pthread.dylib 0x00000001cfbb3cb0 _pthread_start + 320
81 libsystem_pthread.dylib 0x00000001cfbbc778 thread_start + 8
)
2021-04-09 18:11:02.308745+0100 ccc-writer-3[4261:4790641] *** Assertion failure in -[_UISimpleFenceProvider trackSystemAnimationFence:], _UISimpleFenceProvider.m:51
2021-04-09 18:11:02.311976+0100 ccc-writer-3[4261:4790641] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'main thread only'
*** First throw call stack:
(0x184dc686c 0x199de1c50 0x184ccc000 0x18606091c 0x186cd20bc 0x187777d30 0x1877cb888 0x186c00e58 0x1875b2610 0x1871c71b8 0x1871c54d0 0x1871c51f0 0x1871c674c 0x1871c67c8 0x1871c682c 0x187541c94 0x1871c3478 0x1871c2b88 0x1877b7f58 0x1877b2fc8 0x187cb2b30 0x187aacd50 0x100822960 0x100823164 0x1007ec490 0x1008d30b8 0x10055680c 0x100614e6c 0x100610df4 0x100615e98 0x10054e160 0x10055058c 0x100614e6c 0x100611d50 0x10054dfe0 0x100614e6c 0x100610df4 0x10054dfe0 0x100614e6c 0x100610df4 0x100615e98 0x10054e160 0x100550664 0x10054d95c 0x100612888 0x100615e98 0x10060f87c 0x100859f50 0x10085e5dc 0x10085f020 0x100bc7598 0x100bc5c78 0x100beac94 0x100591568 0x1005908dc 0x100c116a0 0x1005908dc 0x100610d94 0x10054dfe0 0x100614e6c 0x100610df4 0x100615e98 0x10054e160 0x10055058c 0x100614e6c 0x100611d50 0x100615e98 0x10060f87c 0x100859f50 0x10085e5dc 0x10085f020 0x100bc7598 0x100bc5c78 0x100bcbdc8 0x100beac94 0x100591568 0x1005908dc 0x100610d94 0x10054dfe0 0x10054d95c 0x100612888 0x10054dfe0 0x100614e6c 0x100610df4 0x10054dfe0 0x100614e6c 0x100610df4 0x10054dfe0 0x1005505f8 0x10054d95c 0x100770c40 0x10065e8e8 0x1cfbb3cb0 0x1cfbbc778)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'main thread only'
terminating with uncaught exception of type NSException
I am not sure what "main thread only" means nor do I have any idea how to resolve this issue. Can anyone clarify what this means and explain what the problem is? How can I stop my program from halting?
Thanks in advance.
I fixed this issue in Xcode by amending the runtime API checking.
Navigate to:
Product > Scheme > Edit Scheme > Run / Debug > Diagnostics
then deselect Main Thread Checker
I'm using ThreadPool for IO-intensive work (such as loading data) while fork a process within the thread if there is CPU-intensive calculation needed. This is my workaround to the GIL problem (anyway, this is not my key problem here).
My problem is: when running my code, sometimes, although a process is folked, it looks always in sleeping status (not even run my calculation). Thus, it causes blocking since the code calls join to wait for result (or error). Note that the problem doesn't always happen, just occasionally.
My running environment is: linux centos 7.3, anaconda 5.1.0 (with built-in python 3.6.4). And note that: i failed to reproduce the issue with the same code on windows.
the following is the simplified code, which can reproduce the issue on linux:
import logging
import time
import random
import os
import threading
from multiprocessing.pool import Pool, ThreadPool
class Task(object):
def __init__(self, func, *args) -> None:
super().__init__()
self.func = func
self.args = args
class ConcurrentExecutor(object):
def __init__(self, spawn_count=1) -> None:
super().__init__()
self.spawn_count = spawn_count
def fork(self, task):
result = None
print('Folk started: %s' % task.args)
pool = Pool(processes=1)
try:
handle = pool.apply_async(task.func, task.args)
pool.close()
result = handle.get()
print('Folk completed: %s' % task.args)
except Exception as err:
print('Fork failure: FOLK%s' % task.args)
raise err
finally:
pool.terminate()
return result
def spawn(self, tasks):
results = []
try:
print('Spawn started')
handles = []
pool = ThreadPool(processes=self.spawn_count)
for task in tasks:
handles.append(pool.apply_async(task.func, task.args))
pool.close()
pool.join()
print('all done')
for handle in handles:
results.append(handle.get(10))
print('Spawn completed')
except Exception as err:
print('Spawn failure')
raise err
return results
def foo_proc(i):
print(i)
result=i*i
time.sleep(1)
return result
def foo(i):
executor = ConcurrentExecutor(2)
try:
result = executor.fork(Task(foo_proc, i))
except Exception as err:
result = 'ERROR'
return result
if __name__ == '__main__':
executor = ConcurrentExecutor(4)
tasks = []
for i in range(1, 10):
tasks.append(Task(foo, i))
start = time.time()
print(executor.spawn(tasks))
end = time.time()
print(end - start)
The following shows an example of running result:
[appadmin#168-61-40-47 test]$ python test.py
7312
Spawn started
Folk started: 1
Folk started: 2
Folk started: 3
Folk started: 4
4
2
1
3
Folk completed: 4
Folk completed: 2
Folk completed: 1
Folk completed: 3
Folk started: 5
Folk started: 6
Folk started: 7
5
Folk started: 8
7
8
Folk completed: 5
Folk completed: 7
Folk completed: 8
Folk started: 9
9
Folk completed: 9
You may see the code was stuck since process "6" was folked but never do the work. Meanwhile, i can see two python processes, which is supposed to be only 1 process at last if everything runs correctly:
[user#x-x-x-x x]$ ps -aux | grep python
user 7312 0.1 0.0 1537216 13524 pts/0 Sl+ 22:23 0:02 python test.py
user 7339 0.0 0.0 1545444 10604 pts/0 S+ 22:23 0:00 python test.py
Could anyone help? Thanks in advance!
I am using Tornado Server, 4.4.2 and pypy 5.9.0 and python 2.7.13,
hosted on Ubuntu 16.04.3 LTS
A new client logs in and a new class is created and passed the socket, so dialog can be maintained. I am using a global clients[] list to contain the classes. initial dialog looks like :
clients = []
class RegisterWebSocket(SockJSConnection):
# intialize the class and handle on-open (some things left out)
def on_open(self,info):
self.ipaddress = info.headers['X-Real-Ip']
def on_message(self, data):
coinlist = []
msg = json.loads(data)
if 'coinlist' in msg:
coinlist = msg['coinlist']
if 'currency' in msg:
currency = msg['currency']
tz = pendulum.timezone('America/New_York')
started = pendulum.now(tz).to_day_datetime_string()
ws = WebClientUpdater(self, self.clientid, coinlist,currency,
started, self.ipaddress)
clients.append(ws)
The ws class is shown below and I use a tornado periodiccallback to update the clients with their specific info every 20 seconds
class WebClientUpdater(SockJSConnection):
def __init__(self, ws,id, clist, currency, started, ipaddress):
super(WebClientUpdater,self).__init__(ws.session)
self.ws = ws
self.id = id
self.coinlist = clist
self.currency = currency
self.started = started
self.ipaddress = ipaddress
self.location = loc
self.loop = tornado.ioloop.PeriodicCallback(self.updateCoinList,
20000, io_loop=tornado.ioloop.IOLoop.instance())
self.loop.start()
self.send_msg('welcome '+ id)
def updateCoinList(self):
pdata = db.getPricesOfCoinsInCurrency(self.coinlist,self.currency)
self.send(dict(priceforcoins = pdata))
def send_msg(self,msg):
self.send(msg)
I also start at 60 second periodiccallback at startup, to monitor the clients for closed connections and remove them from the client[] list. Which I put on the startup line to call a def internally like
if __name__ == "__main__":
app = make_app()
app.listen(options.port)
ScheduleSocketCleaning()
and
def ScheduleSocketCleaning():
def cleanSocketHouse():
print "checking sockets"
for x in clients:
if x.is_closed:
x = None
clients[:] = [y for y in clients if not y.is_closed ]
loop = tornado.ioloop.PeriodicCallback(cleanSocketHouse, 60000,
io_loop=tornado.ioloop.IOLoop.instance())
loop.start()
If I monitor the server using TOP I see that it uses 4% cpu typical with bursts to 60+ immediately, but later, say after a few hours it becomes in the 90% and stays there.
I have used strace and I see an enormous amount of Stat calls on the same files with errors shown in the strace -c view, but I cannot find any errors in a text file using -o trace.log. How can I find those errors ?
But I also notice that most of the time is consumed in epoll_wait.
%time
41.61 0.068097 7 9484 epoll_wait
26.65 0.043617 0 906154 2410 stat
15.77 0.025811 0 524072 read
10.90 0.017840 129 138 brk
2.41 0.003937 9 417 madvise
2.04 0.003340 0 524072 lseek
0.56 0.000923 3 298 sendto
0.06 0.000098 0 23779 gettimeofday
100.00 0.163663 1989527 2410 total
Notice 2410 errors above.
When I view the strace output stream using attached pid, I just see endless Stat calls on the same files..
Can someone advise me as to how to better debug this situation? With only two clients and 20 seconds between client updates, I would expect the CPU usage (there are no other users of the site during this prototype stage) would be less than 1% or thereabouts.
You need to close PeriodicCallbacks, otherwise its a memory leak. You do that by simply calling .close() on a PeriodicCallback object. One way to deal with that is in your periodic cleaning task:
def cleanSocketHouse():
global clients
new_clients = []
for client in clients:
if client.is_closed:
# I don't know why you call it loop,
# .timer would be more appropriate
client.loop.close()
else:
new_clients.append(client)
clients = new_clients
I'm not sure how accurate .is_closed is (some testing is required). The other way is to alter updateCoinList. The .send() method should fail when the client is no longer connected, right? Therefore try: except: should do the trick:
def updateCoinList(self):
global clients
pdata = db.getPricesOfCoinsInCurrency(self.coinlist,self.currency)
try:
self.send(dict(priceforcoins = pdata))
except Exception:
# log exception?
self.loop.close()
clients.remove(self) # you should probably use set instead of list
If ,send() actually doesn't fail (for whatever reason, I'm not that familiar with Tornado) then stick to the first solution.
I'm creating a simple program in python that should save my current processes (using linux and pycharm).
my class code:
class pidSaver:
__pidDictionary={}
def __init__(self):
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
os.kill(int(pid), 0)
except OSError as e:
if e.errno != errno.EPERM: #no premission error
continue
try:
self.__pidDictionary[pid]=open(os.path.join('/proc', pid, 'cmdline'), 'rb').read()
except IOError: # proc has already terminated
continue
def getDic(self):
return self.__pidDictionary
and my main code:
pidsTry = pidSaver()
printList= pidsTry.getDic()
keyList= list(printList.keys())
IntegerKeyList=[]
for key in keyList:
IntegerKeyList.append(int(key))
IntegerKeyList.sort()
for key in IntegerKeyList:
print "%d : %s" %(key ,printList[str(key)])
the output:
1 : /sbin/init
2 :
3 :
5 :
...
7543 : less
...
so from some reason for some of the process I can't get a names and I got a blank out put.
when I run on my computer the command ps -aux | less I got this result:
root 1 0.0 0.0 33776 4256 ? Ss אפר24 0:01 /sbin/init
root 2 0.0 0.0 0 0 ? S אפר24 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S אפר24 0:00 [ksoftirqd/0]
myUser 7543 0.0 0.0 13752 1548 pts/9 T אפר24 0:00 less
so basically, the process that I cannot see in my python are the process that surrounded by "[]".
I don't understand why is this. Also, I want to get them too. how can I do it and why this is happening?
thank you!
These processes you can't see are kernel threads. As the name says they are running in kernel space and are therefore no childs of PID 1, i.e. the init system. Their cmdline is empty because they don't have any corresponding executable that gets called and no arguments to be passed, and this empty cmdline is a pretty safe way to identify them. If you still want to get their name it's in the file /proc/"pid"/status under the name field.