/
art.py
190 lines (140 loc) · 4.74 KB
/
art.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from __future__ import print_function
import psutil
import logging
logging.basicConfig(filename='art.log', level=logging.DEBUG)
import argparse
from random import seed
import sys
try:
from exceptions import KeyboardInterrupt
except ImportError:
pass
from time import sleep, time
from traceback import format_exception
import config
from importer import ImportPlugins
from opc.colors import GRAY50, BLUE
from opc.error import TtyTooSmall
from opc.matrix import OPCMatrix
import opc.utils.prof as prof
from mwt import mwt
DFLT_FLIPTIME_SECS = 30
DFLT_CYCLE_COUNT = None
matrix = None
def matrixDone():
global matrix
if matrix is not None:
try:
matrix.clear()
matrix.show()
except TtyTooSmall:
pass
matrix.terminate()
def exceptionHandler(etype, evalue, etraceback):
matrixDone()
for line in format_exception(etype, evalue, etraceback):
logging.error('Exception: '+line.rstrip('\n'))
if etype is not KeyboardInterrupt:
print("%s (see log for details)" % evalue)
def runart(art, name, args, matrix):
if args.profile:
mem = psutil.virtual_memory()
logging.info("Start %s (%s free mem) ------"%(name, mem.available))
matrix.setFirmwareConfig()
matrix.hq(False)
matrix.clear()
art.start(matrix)
time_sound = 0 # sound as in 'sound as a pound'
time_alarm = 0
start_time = time()
while time()-start_time < args.fliptime:
cycle_time = time()
art.refresh(matrix)
matrix.show()
# interval is between refreshes, but we take time to actually
# render. Account for that here.
debt_time = time()-cycle_time
sleep_time = (art.interval()/1000.0) - debt_time
if sleep_time > 0:
sleep(sleep_time)
time_sound += 1
else:
time_alarm += 1
# timer overrun alarms are an indication that the art has higher
# expectations of the hardware than is reasonable. If you see a
# lot of these, then consider performance tuning, turning up the
# art's interval, or buying better hardware
pc_overrun = 100*time_alarm/(time_sound+time_alarm)
if pc_overrun >= 1:
logging.info("%s: %d%% timer overrun alarms" % (name, pc_overrun))
if args.profile:
fmt = "%-25s %10s %10s %10s %10s %10s %10s"
logging.info(fmt%("Cache", "Length", "Hits", "Misses", "Purged", "Timeouts", "HWM"))
stats = mwt.stats()
for stat in stats:
logging.info(fmt%(stat["cache"], stat["length"], stat["hits"], stat["misses"], stat["purged"], stat["timeouts"], stat["hwm"]))
mwt.reset()
@prof.timereference
def run(arts, args):
global matrix
cycleCount = 0
while args.count is None or cycleCount < args.count:
t=time()
cycleCount += 1
seed(time())
for name, art in arts.items():
runart(art, name, args, matrix)
def _v(attr, default):
try:
return getattr(config, attr)
except:
return default
def progress(index, total):
global matrix
if total < 2:
return
matrix.clear()
height = matrix.height-2
offset = float(height*index)/total
matrix.fillRect(matrix.midWidth-1, 1, 2, height, GRAY50)
matrix.fillRect(matrix.midWidth-1, 1, 2, offset, BLUE)
matrix.show()
def main():
global matrix
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--count", type=int,
help="run for count cycles through all of the art",
default=DFLT_CYCLE_COUNT)
parser.add_argument("-f", "--fliptime", type=int,
help="run art for FLIPTIME secs before transitioning",
default=DFLT_FLIPTIME_SECS)
parser.add_argument("-p", "--profile",
help="switch on and report profiling detail",
action="store_true")
parser.add_argument("art", help="Optional list of arts",
nargs="*")
args = parser.parse_args()
if args.profile:
if args.count:
prof.on()
else:
logging.error("Will not profile without --count being set")
matrix = OPCMatrix(
_v("WIDTH", 16), _v("HEIGHT", 16),
_v("DRIVER", "ansi"), _v("ZIGZAG", False),
_v("FLIPUP", False), _v("FLIPLR", False)
)
progress(0, 10)
arts = ImportPlugins("art", [], args.art, progress,
matrix, config.config)
if len(arts) == 0:
matrix.terminate()
print("Couldn't find any art to execute")
exit(1)
run(arts, args)
matrixDone()
if args.profile:
prof.dumptimings()
if __name__ == "__main__":
sys.excepthook = exceptionHandler
main()