Skip to content

Commit

Permalink
add monotonic utility (#59)
Browse files Browse the repository at this point in the history
* add monotonic utility
* linux only
  • Loading branch information
thijstriemstra authored and rm-hull committed Mar 21, 2017
1 parent 9a4ab7e commit ddba32c
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ htmlcov/
nosetests.xml
coverage.xml

# Eclipse
.project
.pydevproject
.settings/

# Translations
*.mo
*.pot
Expand Down
12 changes: 7 additions & 5 deletions luma/core/sprite_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

from PIL import Image

from luma.core.util import monotonic


class dict_wrapper(object):
"""
Expand Down Expand Up @@ -184,7 +186,7 @@ def __init__(self, fps=16.67):
self.last_time = None

def __enter__(self):
self.enter_time = time.time()
self.enter_time = monotonic()
if not self.start_time:
self.start_time = self.enter_time
self.last_time = self.enter_time
Expand All @@ -199,15 +201,15 @@ def __exit__(self, *args):
it simply exits without blocking.
"""
self.called += 1
self.total_transit_time += time.time() - self.enter_time
self.total_transit_time += monotonic() - self.enter_time
if self.max_sleep_time >= 0:
elapsed = time.time() - self.last_time
elapsed = monotonic() - self.last_time
sleep_for = self.max_sleep_time - elapsed

if sleep_for > 0:
time.sleep(sleep_for)

self.last_time = time.time()
self.last_time = monotonic()

def effective_FPS(self):
"""
Expand All @@ -218,7 +220,7 @@ def effective_FPS(self):
:returns: the effective frame rate
:rtype: float
"""
elapsed = time.time() - self.start_time
elapsed = monotonic() - self.start_time
return self.called / elapsed

def average_transit_time(self):
Expand Down
34 changes: 33 additions & 1 deletion luma/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,42 @@
# Copyright (c) 2017 Richard Hull and contributors
# See LICENSE.rst for details.

import os
import time
import warnings
import ctypes.util


__all__ = ["deprecation"]
__all__ = ["deprecation", "monotonic"]


try:
# only available since python 3.3
monotonic = time.monotonic
except AttributeError:
try:
clock_gettime = ctypes.CDLL(ctypes.util.find_library('c'),
use_errno=True).clock_gettime
except AttributeError:
clock_gettime = ctypes.CDLL(ctypes.util.find_library('rt'),
use_errno=True).clock_gettime

class timespec(ctypes.Structure):
"""
Time specification, as described in clock_gettime(3).
"""
_fields_ = (('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long))

def monotonic():
"""
Monotonic clock that cannot go backward.
"""
ts = timespec()
if clock_gettime(1, ctypes.pointer(ts)):
errno = ctypes.get_errno()
raise OSError(errno, os.strerror(errno))
return ts.tv_sec + ts.tv_nsec / 1.0e9


def deprecation(message):
Expand Down
8 changes: 5 additions & 3 deletions luma/core/virtual.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from PIL import Image, ImageDraw, ImageFont

from luma.core.util import monotonic
from luma.core import mixin, ansi_color
from luma.core.threadpool import threadpool

Expand Down Expand Up @@ -169,19 +170,20 @@ def should_redraw(self):
"""
Only requests a redraw after ``interval`` seconds have elapsed
"""
return time.time() - self.last_updated > self.interval
return monotonic() - self.last_updated > self.interval

def paste_into(self, image, xy):
super(snapshot, self).paste_into(image, xy)
self.last_updated = time.time()
self.last_updated = monotonic()


class terminal(object):
"""
Provides a terminal-like interface to a device (or a device-like object
that has :class:`mixin.capabilities` characteristics).
"""
def __init__(self, device, font=None, color="white", bgcolor="black", tabstop=4, line_height=None, animate=True):
def __init__(self, device, font=None, color="white", bgcolor="black",
tabstop=4, line_height=None, animate=True):
self._device = device
self.font = font or ImageFont.load_default()
self.default_fgcolor = color
Expand Down
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ def read_file(fname):
download_url="https://github.com/rm-hull/luma.core/tarball/" + version,
namespace_packages=["luma"],
packages=["luma.core", "luma.core.legacy"],
install_requires=["pillow>=4.0.0", "smbus2", "spidev", "RPi.GPIO"],
install_requires=[
"pillow>=4.0.0",
"smbus2",
"spidev",
"RPi.GPIO"
],
setup_requires=pytest_runner,
tests_require=test_deps,
extras_require={
Expand Down
19 changes: 9 additions & 10 deletions tests/test_framerate_regulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
Tests for the :py:class:`luma.core.sprite_system.framerate_regulator` class.
"""

import time

import pytest

from luma.core.util import monotonic
from luma.core.sprite_system import framerate_regulator


Expand All @@ -19,10 +18,10 @@ def test_init_default():
assert regulator.start_time is None
assert regulator.last_time is None
assert regulator.called == 0
before = time.time()
before = monotonic()
with regulator:
pass
after = time.time()
after = monotonic()

assert regulator.max_sleep_time == 1 / 16.67
assert before <= regulator.start_time <= after
Expand All @@ -31,10 +30,10 @@ def test_init_default():

def test_init_unlimited():
regulator = framerate_regulator(fps=0)
before = time.time()
before = monotonic()
with regulator:
pass
after = time.time()
after = monotonic()

assert regulator.max_sleep_time == -1
assert before <= regulator.start_time <= after
Expand All @@ -43,10 +42,10 @@ def test_init_unlimited():

def test_init_30fps():
regulator = framerate_regulator(fps=30)
before = time.time()
before = monotonic()
with regulator:
pass
after = time.time()
after = monotonic()

assert regulator.max_sleep_time == 1 / 30.00
assert before <= regulator.start_time <= after
Expand All @@ -55,11 +54,11 @@ def test_init_30fps():

def test_sleep():
regulator = framerate_regulator(fps=100.00)
before = time.time()
before = monotonic()
for _ in range(200):
with regulator:
pass
after = time.time()
after = monotonic()

assert regulator.called == 200
assert after - before >= 2.0
Expand Down

0 comments on commit ddba32c

Please sign in to comment.