Fastest way to get system uptime in Python in Linux
I don't think you can get much faster than using ctypes
to call sysinfo()
but in my tests, its slower than /proc. Those linux system programmers seem to know what they are doing!
import ctypes
import struct
def uptime3():
libc = ctypes.CDLL('libc.so.6')
buf = ctypes.create_string_buffer(4096) # generous buffer to hold
# struct sysinfo
if libc.sysinfo(buf) != 0:
print('failed')
return -1
uptime = struct.unpack_from('@l', buf.raw)[0]
return uptime
Running your two tests plus mine on my slow laptop, I got:
>>> print(timeit.timeit('ut.uptime1()', setup="import uptimecalls as ut", number=1000))
5.284219555993332
>>> print(timeit.timeit('ut.uptime2()', setup="import uptimecalls as ut", number=1000))
0.1044210599939106
>>> print(timeit.timeit('ut.uptime3()', setup="import uptimecalls as ut", number=1000))
0.11733305400412064
UPDATE
Most of the time is spent pulling in libc
and creating the buffer. If you plan to make the call repeatedly over time, then you can pull those steps out of the function and measure just the system call. In that case, this solution is the clear winner:
uptime1: 5.066633300986723
uptime2: 0.11561189399799332
uptime3: 0.007740753993857652
get system uptime with Python on a Raspberry Pi
I found another solution: https://www.raspberrypi.org/forums/viewtopic.php?t=164276
#!/usr/bin/python3
import shlex, subprocess
cmd = "uptime -p"
args = shlex.split(cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE)
output = p.communicate()
Thanks for your posted ideas.
print (output)
How to retrieve the process start time (or uptime) in python
If you are doing it from within the python program you're trying to measure, you could do something like this:
import time
# at the beginning of the script
startTime = time.time()
# ...
def getUptime():
"""
Returns the number of seconds since the program started.
"""
# do return startTime if you just want the process start time
return time.time() - startTime
Otherwise, you have no choice but to parse ps
or go into /proc/pid
. A nice bash
y way of getting the elapsed time is:
ps -eo pid,etime | grep $YOUR_PID | awk '{print $2}'
This will only print the elapsed time in the following format, so it should be quite easy to parse:
days-HH:MM:SS
(if it's been running for less than a day, it's just HH:MM:SS
)
The start time is available like this:
ps -eo pid,stime | grep $YOUR_PID | awk '{print $2}'
Unfortunately, if your process didn't start today, this will only give you the date that it started, rather than the time.
The best way of doing this is to get the elapsed time and the current time and just do a bit of math. The following is a python script that takes a PID as an argument and does the above for you, printing out the start date and time of the process:
import sys
import datetime
import time
import subprocess
# call like this: python startTime.py $PID
pid = sys.argv[1]
proc = subprocess.Popen(['ps','-eo','pid,etime'], stdout=subprocess.PIPE)
# get data from stdout
proc.wait()
results = proc.stdout.readlines()
# parse data (should only be one)
for result in results:
try:
result.strip()
if result.split()[0] == pid:
pidInfo = result.split()[1]
# stop after the first one we find
break
except IndexError:
pass # ignore it
else:
# didn't find one
print "Process PID", pid, "doesn't seem to exist!"
sys.exit(0)
pidInfo = [result.split()[1] for result in results
if result.split()[0] == pid][0]
pidInfo = pidInfo.partition("-")
if pidInfo[1] == '-':
# there is a day
days = int(pidInfo[0])
rest = pidInfo[2].split(":")
hours = int(rest[0])
minutes = int(rest[1])
seconds = int(rest[2])
else:
days = 0
rest = pidInfo[0].split(":")
if len(rest) == 3:
hours = int(rest[0])
minutes = int(rest[1])
seconds = int(rest[2])
elif len(rest) == 2:
hours = 0
minutes = int(rest[0])
seconds = int(rest[1])
else:
hours = 0
minutes = 0
seconds = int(rest[0])
# get the start time
secondsSinceStart = days*24*3600 + hours*3600 + minutes*60 + seconds
# unix time (in seconds) of start
startTime = time.time() - secondsSinceStart
# final result
print "Process started on",
print datetime.datetime.fromtimestamp(startTime).strftime("%a %b %d at %I:%M:%S %p")
Getting the linux time since power on
you can use "tuptime| grep -i 'system life'"
in the cmd instead of "tuptime"
How can I get an equivalent of Python threading.Timer that uses system uptime?
Update
What I am doing now is to monkey patch threading._time
with a monotonic function from the monotonic
package on PyPI.
import threading
import monotonic
threading._time = monotonic.monotonic
Original answer
I ended up extending threading.Timer
to use system uptime.
class Timer(threading._Timer):
def __init__(self, *args, **kwargs):
super(Timer, self).__init__(*args, **kwargs)
# only works on Linux
self._libc = ctypes.CDLL('libc.so.6')
self._buf = ctypes.create_string_buffer(128)
def uptime(self):
self._libc.sysinfo(self._buf)
return struct.unpack_from('@l', self._buf.raw)[0]
def run(self):
start_time = self.uptime()
while not self.finished.is_set():
time.sleep(0.1)
if self.uptime() - start_time > self.interval:
self.function(*self.args, **self.kwargs)
break
self.finished.set()
How do I get Linux system's up-time?
#include <stdio.h>
#include <sys/sysinfo.h>
int main(void)
{
struct sysinfo sys_info;
sysinfo(&sys_info);
printf("Seconds since uptime: %lu\n", sys_info.uptime);
return 0;
}
This should get you started. If you need more help, type man sysinfo
into the terminal.
What API do I call to get the system uptime?
The system call you're looking for is sysinfo().
It's defined in sys/sysinfo.h
Its signature is:
int sysinfo(struct sysinfo *info)
Since kernel 2.4, the structure has looked like this:
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding for libc5 */
};
Have fun!
Bash format uptime to show days, hours, minutes
My uptime
produces output that looks like:
$ uptime
12:49:10 up 25 days, 21:30, 28 users, load average: 0.50, 0.66, 0.52
To convert that to your format:
$ uptime | awk -F'( |,|:)+' '{print $6,$7",",$8,"hours,",$9,"minutes."}'
25 days, 21 hours, 34 minutes.
How it works
-F'( |,|:)+'
awk divides its input up into fields. This tells awk to use any combination of one or more of space, comma, or colon as the field separator.
print $6,$7",",$8,"hours,",$9,"minutes."
This tells awk to print the sixth field and seventh fields (separated by a space) followed by a comma, the 8th field, the string
hours,
the ninth field, and, lastly, the stringminutes.
.
Handling computers with short uptimes using sed
Starting from a reboot, my uptime
produces output like:
03:14:20 up 1 min, 2 users, load average: 2.28, 1.29, 0.50
04:12:29 up 59 min, 5 users, load average: 0.06, 0.08, 0.48
05:14:09 up 2:01, 5 users, load average: 0.13, 0.10, 0.45
03:13:19 up 1 day, 0 min, 8 users, load average: 0.01, 0.04, 0.05
04:13:19 up 1 day, 1:00, 8 users, load average: 0.02, 0.05, 0.21
12:49:10 up 25 days, 21:30, 28 users, load average: 0.50, 0.66, 0.52
The following sed
command handles these formats:
uptime | sed -E 's/^[^,]*up *//; s/, *[[:digit:]]* users.*//; s/min/minutes/; s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/'
With the above times, this produces:
1 minutes
59 minutes
2 hours, 1 minutes
1 day, 0 minutes
1 day, 1 hours, 0 minutes
25 days, 21 hours, 30 minutes
How it works
-E
turns on extended regular expression syntax. (On older GNU seds, use-r
in place of-E
)s/^[^,]*up *//
This substitutes command removes all text up to
up
.s/, *[[:digit:]]* users.*//
This substitute command removes the user count and all text which follows it.
s/min/minutes/
This replaces
min
withminutes
.s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/'
If the line contains a time in the hh:mm format, this separates the hours from the minutes and replaces it with
hh hours, mm minutes
.
Handling computers with short uptimes using awk
uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'
On the same test cases as above, this produces:
0 days, 0 hours, 1 minutes.
0 days, 0 hours, 59 minutes.
0 days, 2 hours, 1 minutes.
1 days, 0 hours, 0 minutes.
1 days, 1 hours, 0 minutes.
25 days, 21 hours, 30 minutes.
For those who prefer awk code spread out over multiple lines:
uptime | awk -F'( |,|:)+' '{
d=h=m=0;
if ($7=="min")
m=$6;
else {
if ($7~/^day/) { d=$6; h=$8; m=$9}
else {h=$6;m=$7}
}
}
{
print d+0,"days,",h+0,"hours,",m+0,"minutes."
}'
Related Topics
How to Declare Custom Exceptions in Modern Python
How to Convert Index of a Pandas Dataframe into a Column
CSS Problems with Flask Web App
Google App Engine: Won't Serve Static Assets with Below Error:
Total Memory Used by Python Process
How to Write a 'Try'/'Except' Block That Catches All Exceptions
Get Last N Lines of a File, Similar to Tail
How to Extract a Floating Number from a String
How to Join Two Dataframes For Which Column Values Are Within a Certain Range
How to Import the Class Within the Same Directory or Sub Directory
Check If All Elements in a List Are Identical
Change Working Directory in Shell with a Python Script
How to Select a Specific Input Device with Pyaudio
Behaviour of Increment and Decrement Operators in Python
How to Sort Pandas Dataframe from One Column