Comments (10)
I'm on holiday at the moment, so can't immediately try anything. You could try running the python profiler, by adding -m cProfile
to the python command line. See here for an example: http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script
And paste the results as a new comment.
from luma.oled.
Thanks for replying during your holidays! I've noticed that some of the CPU is because of the program loading, but still some load after everything is running.
Here the trace from the demo.py, I just modified the code to loop 5 times the with canvas(device) as draw:
(oledEnv)mike@localhost~/ssd1306/examples $ time python -m cProfile demoLoop5.py
11110 function calls (11089 primitive calls) in 1.561 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 BmpImagePlugin.py:202(DibImageFile)
1 0.011 0.011 0.020 0.020 BmpImagePlugin.py:27(<module>)
6 0.000 0.000 0.000 0.000 BmpImagePlugin.py:56(_accept)
1 0.000 0.000 0.000 0.000 BmpImagePlugin.py:63(BmpImageFile)
1 0.005 0.005 0.048 0.048 FixTk.py:1(<module>)
1 0.006 0.006 0.007 0.007 GifImagePlugin.py:27(<module>)
6 0.000 0.000 0.000 0.000 GifImagePlugin.py:44(_accept)
1 0.000 0.000 0.000 0.000 GifImagePlugin.py:52(GifImageFile)
5 0.000 0.000 0.001 0.000 Image.py:1133(getdata)
1 0.000 0.000 0.000 0.000 Image.py:1966(_ImageCrop)
1 0.000 0.000 0.000 0.000 Image.py:2002(ImagePointHandler)
1 0.000 0.000 0.000 0.000 Image.py:2007(ImageTransformHandler)
5 0.001 0.000 0.003 0.001 Image.py:2024(new)
6 0.000 0.000 0.000 0.000 Image.py:2250(_decompression_bomb_check)
6 0.002 0.000 0.106 0.018 Image.py:2264(open)
6 0.000 0.000 0.001 0.000 Image.py:2436(register_open)
5 0.000 0.000 0.000 0.000 Image.py:2451(register_mime)
6 0.000 0.000 0.000 0.000 Image.py:2462(register_save)
1 0.000 0.000 0.000 0.000 Image.py:2473(register_save_all)
12 0.000 0.000 0.001 0.000 Image.py:2485(register_extension)
1 0.038 0.038 0.176 0.176 Image.py:27(<module>)
1 0.000 0.000 0.000 0.000 Image.py:34(DecompressionBombWarning)
6 0.013 0.002 0.088 0.015 Image.py:343(preinit)
1 0.000 0.000 0.000 0.000 Image.py:38(_imaging_not_installed)
6 0.000 0.000 0.001 0.000 Image.py:406(_getdecoder)
1 0.000 0.000 0.000 0.000 Image.py:447(_E)
1 0.001 0.001 0.001 0.001 Image.py:482(Image)
16 0.001 0.000 0.001 0.000 Image.py:496(__init__)
5 0.001 0.000 0.001 0.000 Image.py:516(_new)
23 0.001 0.000 0.001 0.000 Image.py:623(__getattr__)
22 0.001 0.000 0.001 0.000 Image.py:760(load)
1 0.000 0.000 0.000 0.000 ImageChops.py:18(<module>)
1 0.001 0.001 0.001 0.001 ImageColor.py:20(<module>)
45 0.003 0.000 0.007 0.000 ImageDraw.py:138(_getink)
5 0.001 0.000 0.011 0.002 ImageDraw.py:191(ellipse)
10 0.001 0.000 0.002 0.000 ImageDraw.py:201(line)
5 0.000 0.000 0.002 0.000 ImageDraw.py:239(polygon)
10 0.001 0.000 0.004 0.000 ImageDraw.py:249(rectangle)
15 0.000 0.000 0.001 0.000 ImageDraw.py:259(_multiline_check)
15 0.003 0.000 0.007 0.000 ImageDraw.py:269(text)
1 0.003 0.003 0.004 0.004 ImageDraw.py:33(<module>)
5 0.001 0.000 0.003 0.001 ImageDraw.py:345(Draw)
1 0.000 0.000 0.000 0.000 ImageDraw.py:50(ImageDraw)
5 0.001 0.000 0.001 0.000 ImageDraw.py:62(__init__)
6 0.005 0.001 0.014 0.002 ImageFile.py:130(load)
6 0.000 0.000 0.001 0.000 ImageFile.py:262(load_prepare)
1 0.000 0.000 0.000 0.000 ImageFile.py:284(StubImageFile)
1 0.005 0.005 0.005 0.005 ImageFile.py:30(<module>)
1 0.000 0.000 0.000 0.000 ImageFile.py:314(Parser)
6 0.000 0.000 0.000 0.000 ImageFile.py:506(_safe_read)
6 0.000 0.000 0.000 0.000 ImageFile.py:66(_tilesort)
1 0.000 0.000 0.000 0.000 ImageFile.py:75(ImageFile)
6 0.001 0.000 0.014 0.002 ImageFile.py:78(__init__)
1 0.000 0.000 0.000 0.000 ImageFont.py:121(FreeTypeFont)
1 0.000 0.000 0.000 0.000 ImageFont.py:194(TransposedFont)
1 0.009 0.009 0.010 0.010 ImageFont.py:28(<module>)
6 0.006 0.001 0.143 0.024 ImageFont.py:326(load_default)
1 0.000 0.000 0.000 0.000 ImageFont.py:39(_imagingft_not_installed)
1 0.000 0.000 0.000 0.000 ImageFont.py:65(ImageFont)
6 0.002 0.000 0.017 0.003 ImageFont.py:88(_load_pilfont_data)
1 0.001 0.001 0.001 0.001 ImageMode.py:17(<module>)
1 0.000 0.000 0.000 0.000 ImageMode.py:23(ModeDescriptor)
1 0.003 0.003 0.004 0.004 ImagePalette.py:19(<module>)
1 0.000 0.000 0.000 0.000 ImagePalette.py:24(ImagePalette)
1 0.001 0.001 0.001 0.001 ImageSequence.py:19(<module>)
1 0.000 0.000 0.000 0.000 ImageSequence.py:19(Iterator)
6 0.000 0.000 0.000 0.000 JpegImagePlugin.py:274(_accept)
1 0.000 0.000 0.000 0.000 JpegImagePlugin.py:281(JpegImageFile)
1 0.007 0.007 0.017 0.017 JpegImagePlugin.py:35(<module>)
1 0.000 0.000 0.000 0.000 JpegPresets.py:67(<module>)
12 0.001 0.000 0.002 0.000 PngImagePlugin.py:104(read)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:122(close)
12 0.001 0.000 0.005 0.000 PngImagePlugin.py:129(call)
6 0.001 0.000 0.002 0.000 PngImagePlugin.py:136(crc)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:167(iTXt)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:187(PngInfo)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:264(PngStream)
6 0.001 0.000 0.001 0.000 PngImagePlugin.py:266(__init__)
6 0.001 0.000 0.002 0.000 PngImagePlugin.py:310(chunk_IHDR)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:325(chunk_IDAT)
1 0.009 0.009 0.023 0.023 PngImagePlugin.py:34(<module>)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:476(_accept)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:483(PngImageFile)
6 0.002 0.000 0.013 0.002 PngImagePlugin.py:488(_open)
6 0.001 0.000 0.001 0.000 PngImagePlugin.py:549(load_prepare)
6 0.000 0.000 0.001 0.000 PngImagePlugin.py:557(load_read)
6 0.000 0.000 0.001 0.000 PngImagePlugin.py:583(load_end)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:626(_idat)
1 0.000 0.000 0.000 0.000 PngImagePlugin.py:94(ChunkStream)
6 0.000 0.000 0.000 0.000 PngImagePlugin.py:96(__init__)
1 0.002 0.002 0.008 0.008 PpmImagePlugin.py:18(<module>)
6 0.000 0.000 0.000 0.000 PpmImagePlugin.py:52(_accept)
1 0.000 0.000 0.000 0.000 PpmImagePlugin.py:59(PpmImageFile)
6 0.000 0.000 0.000 0.000 TiffImagePlugin.py:221(_accept)
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:228(ImageFileDirectory)
1 0.005 0.005 0.009 0.009 TiffImagePlugin.py:42(<module>)
1 0.000 0.000 0.000 0.000 TiffImagePlugin.py:630(TiffImageFile)
1 0.000 0.000 0.000 0.000 UserDict.py:18(__getitem__)
3 0.000 0.000 0.000 0.000 UserDict.py:58(get)
3 0.000 0.000 0.000 0.000 UserDict.py:70(__contains__)
1 0.000 0.000 0.000 0.000 __future__.py:48(<module>)
1 0.000 0.000 0.000 0.000 __future__.py:74(_Feature)
7 0.000 0.000 0.000 0.000 __future__.py:75(__init__)
2 0.014 0.007 0.038 0.019 __init__.py:1(<module>)
3 0.000 0.000 0.000 0.000 __init__.py:104(CFunctionType)
1 0.000 0.000 0.000 0.000 __init__.py:14(<module>)
14 0.002 0.000 0.003 0.000 __init__.py:147(_check_size)
1 0.000 0.000 0.000 0.000 __init__.py:159(py_object)
1 0.000 0.000 0.000 0.000 __init__.py:168(c_short)
1 0.000 0.000 0.000 0.000 __init__.py:172(c_ushort)
1 0.000 0.000 0.000 0.000 __init__.py:176(c_long)
1 0.000 0.000 0.000 0.000 __init__.py:180(c_ulong)
1 0.000 0.000 0.000 0.000 __init__.py:197(c_float)
1 0.000 0.000 0.000 0.000 __init__.py:201(c_double)
1 0.000 0.000 0.000 0.000 __init__.py:205(c_longdouble)
1 0.000 0.000 0.000 0.000 __init__.py:215(c_longlong)
1 0.000 0.000 0.000 0.000 __init__.py:219(c_ulonglong)
1 0.000 0.000 0.000 0.000 __init__.py:226(c_ubyte)
1 0.000 0.000 0.000 0.000 __init__.py:233(c_byte)
1 0.000 0.000 0.000 0.000 __init__.py:238(c_char)
1 0.000 0.000 0.000 0.000 __init__.py:243(c_char_p)
1 0.000 0.000 0.000 0.000 __init__.py:255(c_void_p)
1 0.000 0.000 0.000 0.000 __init__.py:260(c_bool)
1 0.001 0.001 0.003 0.003 __init__.py:265(_reset_cache)
1 0.000 0.000 0.000 0.000 __init__.py:291(c_wchar_p)
1 0.000 0.000 0.000 0.000 __init__.py:294(c_wchar)
1 0.000 0.000 0.000 0.000 __init__.py:3(<module>)
1 0.000 0.000 0.000 0.000 __init__.py:332(CDLL)
1 0.001 0.001 0.001 0.001 __init__.py:349(__init__)
1 0.000 0.000 0.000 0.000 __init__.py:359(_FuncPtr)
1 0.000 0.000 0.000 0.000 __init__.py:388(PyDLL)
1 0.029 0.029 0.042 0.042 __init__.py:4(<module>)
1 0.000 0.000 0.000 0.000 __init__.py:428(LibraryLoader)
2 0.000 0.000 0.000 0.000 __init__.py:429(__init__)
2 0.000 0.000 0.000 0.000 __init__.py:49(normalize_encoding)
3 0.002 0.001 0.002 0.001 __init__.py:493(PYFUNCTYPE)
3 0.000 0.000 0.000 0.000 __init__.py:494(CFunctionType)
1 0.000 0.000 0.004 0.004 __init__.py:71(search_function)
3 0.002 0.001 0.002 0.001 __init__.py:78(CFUNCTYPE)
1 0.000 0.000 0.000 0.000 _binary.py:14(<module>)
24 0.000 0.000 0.000 0.000 _binary.py:17(i8)
12 0.000 0.000 0.000 0.000 _binary.py:52(i16be)
24 0.001 0.000 0.001 0.000 _binary.py:56(i32be)
1 0.000 0.000 0.000 0.000 _endian.py:26(_swapped_meta)
1 0.002 0.002 0.002 0.002 _endian.py:4(<module>)
1 0.000 0.000 0.000 0.000 _endian.py:49(BigEndianStructure)
1 0.001 0.001 0.001 0.001 _util.py:1(<module>)
1 0.000 0.000 0.000 0.000 _util.py:22(deferred_error)
70 0.001 0.000 0.003 0.000 _util.py:4(isStringType)
12 0.000 0.000 0.001 0.000 _util.py:7(isPath)
12 0.000 0.000 0.000 0.000 _weakrefset.py:16(__init__)
12 0.000 0.000 0.001 0.000 _weakrefset.py:20(__enter__)
12 0.001 0.000 0.001 0.000 _weakrefset.py:26(__exit__)
38 0.003 0.000 0.003 0.000 _weakrefset.py:36(__init__)
12 0.000 0.000 0.000 0.000 _weakrefset.py:52(_commit_removals)
24 0.001 0.000 0.003 0.000 _weakrefset.py:58(__iter__)
16 0.000 0.000 0.000 0.000 _weakrefset.py:70(__contains__)
24 0.001 0.000 0.001 0.000 _weakrefset.py:83(add)
12 0.001 0.000 0.011 0.001 abc.py:105(register)
12 0.003 0.000 0.008 0.001 abc.py:148(__subclasscheck__)
37 0.001 0.000 0.001 0.000 abc.py:15(abstractmethod)
10 0.007 0.001 0.021 0.002 abc.py:86(__new__)
51 0.002 0.000 0.004 0.000 abc.py:89(<genexpr>)
1 0.003 0.003 0.004 0.004 api.py:1(<module>)
1 0.000 0.000 0.000 0.000 api.py:18(FFIError)
1 0.000 0.000 0.000 0.000 api.py:21(CDefError)
1 0.000 0.000 0.000 0.000 api.py:30(FFI)
1 0.000 0.000 0.000 0.000 ascii.py:13(Codec)
1 0.000 0.000 0.000 0.000 ascii.py:20(IncrementalEncoder)
1 0.000 0.000 0.000 0.000 ascii.py:24(IncrementalDecoder)
1 0.000 0.000 0.000 0.000 ascii.py:28(StreamWriter)
1 0.000 0.000 0.000 0.000 ascii.py:31(StreamReader)
1 0.000 0.000 0.000 0.000 ascii.py:34(StreamConverter)
1 0.000 0.000 0.000 0.000 ascii.py:41(getregentry)
1 0.002 0.002 0.002 0.002 ascii.py:8(<module>)
1 0.007 0.007 0.009 0.009 base64.py:3(<module>)
12 0.000 0.000 0.004 0.000 base64.py:319(decodestring)
1 0.000 0.000 0.000 0.000 codecs.py:83(__new__)
1 0.011 0.011 0.021 0.021 collections.py:1(<module>)
1 0.000 0.000 0.000 0.000 collections.py:26(OrderedDict)
1 0.000 0.000 0.000 0.000 collections.py:395(Counter)
1 0.031 0.031 1.561 1.561 demoLoop5.py:6(<module>)
1 0.000 0.000 0.000 0.000 device.py:149(ssd1306)
1 0.000 0.000 0.005 0.005 device.py:157(__init__)
5 0.427 0.085 1.114 0.223 device.py:181(display)
1 0.000 0.000 0.000 0.000 device.py:210(const)
1 0.007 0.007 0.026 0.026 device.py:53(<module>)
1 0.000 0.000 0.000 0.000 device.py:56(device)
1 0.000 0.000 0.001 0.001 device.py:61(__init__)
6 0.001 0.000 0.013 0.002 device.py:67(command)
5 0.018 0.004 0.655 0.131 device.py:75(data)
1 0.000 0.000 0.000 0.000 device.py:87(sh1106)
1 0.005 0.005 0.005 0.005 ffiplatform.py:1(<module>)
1 0.000 0.000 0.000 0.000 ffiplatform.py:4(VerificationError)
1 0.000 0.000 0.000 0.000 ffiplatform.py:8(VerificationMissing)
2 0.000 0.000 0.000 0.000 genericpath.py:23(exists)
1 0.009 0.009 0.009 0.009 heapq.py:31(<module>)
1 0.010 0.010 0.024 0.024 io.py:34(<module>)
1 0.000 0.000 0.000 0.000 io.py:69(IOBase)
1 0.000 0.000 0.000 0.000 io.py:73(RawIOBase)
1 0.000 0.000 0.000 0.000 io.py:76(BufferedIOBase)
1 0.000 0.000 0.000 0.000 io.py:79(TextIOBase)
1 0.000 0.000 0.000 0.000 keyword.py:11(<module>)
1 0.000 0.000 0.000 0.000 locale.py:347(_replace_encoding)
2 0.000 0.000 0.001 0.000 locale.py:363(normalize)
2 0.000 0.000 0.001 0.000 locale.py:447(_parse_localename)
1 0.001 0.001 0.002 0.002 locale.py:493(getdefaultlocale)
1 0.000 0.000 0.000 0.000 locale.py:546(getlocale)
1 0.000 0.000 0.000 0.000 lock.py:1(<module>)
1 0.000 0.000 0.000 0.000 numbers.py:13(Number)
1 0.000 0.000 0.000 0.000 numbers.py:169(Real)
1 0.000 0.000 0.000 0.000 numbers.py:270(Rational)
1 0.002 0.002 0.002 0.002 numbers.py:295(Integral)
1 0.000 0.000 0.001 0.001 numbers.py:34(Complex)
1 0.001 0.001 0.020 0.020 numbers.py:6(<module>)
1 0.000 0.000 0.000 0.000 posixpath.py:329(normpath)
1 0.000 0.000 0.000 0.000 posixpath.py:358(abspath)
1 0.000 0.000 0.000 0.000 posixpath.py:52(isabs)
2 0.000 0.000 0.000 0.000 posixpath.py:61(join)
3 0.000 0.000 0.014 0.005 re.py:192(compile)
3 0.001 0.000 0.013 0.004 re.py:230(_compile)
1 0.018 0.018 0.198 0.198 render.py:53(<module>)
1 0.000 0.000 0.000 0.000 render.py:56(canvas)
5 0.000 0.000 0.003 0.001 render.py:62(__init__)
5 0.000 0.000 0.003 0.001 render.py:67(__enter__)
5 0.003 0.001 1.117 0.223 render.py:71(__exit__)
166 0.022 0.000 0.607 0.004 smbus.py:261(write_i2c_block_data)
1 0.014 0.014 0.016 0.016 smbus.py:27(<module>)
166 0.050 0.000 0.052 0.000 smbus.py:296(list_to_smbus_data)
1 0.001 0.001 0.002 0.002 smbus.py:41(SMBus)
1 0.000 0.000 0.000 0.000 smbus.py:54(__init__)
1 0.000 0.000 0.000 0.000 smbus.py:71(open)
166 0.002 0.000 0.002 0.000 smbus.py:85(_set_addr)
5 0.000 0.000 0.001 0.000 sre_compile.py:228(_compile_charset)
5 0.001 0.000 0.001 0.000 sre_compile.py:256(_optimize_charset)
3 0.000 0.000 0.000 0.000 sre_compile.py:428(_simple)
3 0.000 0.000 0.002 0.001 sre_compile.py:433(_compile_info)
6 0.000 0.000 0.000 0.000 sre_compile.py:546(isstring)
3 0.000 0.000 0.006 0.002 sre_compile.py:552(_code)
3 0.001 0.000 0.012 0.004 sre_compile.py:567(compile)
6/3 0.001 0.000 0.003 0.001 sre_compile.py:64(_compile)
12 0.000 0.000 0.000 0.000 sre_parse.py:137(__len__)
18 0.001 0.000 0.001 0.000 sre_parse.py:141(__getitem__)
3 0.000 0.000 0.000 0.000 sre_parse.py:145(__setitem__)
12 0.000 0.000 0.000 0.000 sre_parse.py:149(append)
9/6 0.001 0.000 0.001 0.000 sre_parse.py:151(getwidth)
3 0.000 0.000 0.000 0.000 sre_parse.py:189(__init__)
24 0.001 0.000 0.001 0.000 sre_parse.py:193(__next)
6 0.000 0.000 0.000 0.000 sre_parse.py:206(match)
21 0.000 0.000 0.001 0.000 sre_parse.py:212(get)
4 0.000 0.000 0.000 0.000 sre_parse.py:268(_escape)
3 0.000 0.000 0.005 0.002 sre_parse.py:317(_parse_sub)
3 0.002 0.001 0.005 0.002 sre_parse.py:395(_parse)
3 0.000 0.000 0.000 0.000 sre_parse.py:67(__init__)
3 0.000 0.000 0.006 0.002 sre_parse.py:706(parse)
6 0.000 0.000 0.000 0.000 sre_parse.py:92(__init__)
1 0.000 0.000 0.000 0.000 traceback.py:1(<module>)
1 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
1 0.001 0.001 0.001 0.001 util.py:1(<module>)
5 0.000 0.000 0.000 0.000 util.py:14(get_validator)
498 0.008 0.000 0.011 0.000 util.py:15(f)
13 0.000 0.000 0.000 0.000 util.py:27(validate)
13 0.001 0.000 0.001 0.000 util.py:28(wrapper)
166 0.029 0.000 0.648 0.004 util.py:39(validator)
12 0.000 0.000 0.000 0.000 {PIL._imaging.crc32}
5 0.000 0.000 0.000 0.000 {PIL._imaging.draw}
5 0.000 0.000 0.000 0.000 {PIL._imaging.fill}
6 0.001 0.000 0.001 0.000 {PIL._imaging.font}
6 0.000 0.000 0.000 0.000 {PIL._imaging.new}
6 0.000 0.000 0.000 0.000 {PIL._imaging.zip_decoder}
2 0.004 0.002 0.054 0.027 {__import__}
1 0.000 0.000 0.000 0.000 {_codecs.utf_8_decode}
2 0.001 0.001 0.001 0.001 {_ctypes.POINTER}
1 0.000 0.000 0.000 0.000 {_ctypes.dlopen}
1 0.000 0.000 0.000 0.000 {_ctypes.set_conversion_mode}
34 0.000 0.000 0.000 0.000 {_ctypes.sizeof}
1 0.000 0.000 0.000 0.000 {_locale.setlocale}
3 0.000 0.000 0.000 0.000 {_sre.compile}
18 0.001 0.000 0.001 0.000 {_struct.calcsize}
36 0.001 0.000 0.001 0.000 {_struct.unpack}
12 0.004 0.000 0.004 0.000 {binascii.a2b_base64}
11 0.005 0.000 0.005 0.000 {built-in method __new__ of type object at 0x152d10}
166 0.523 0.003 0.523 0.003 {built-in method i2c_smbus_access}
422 0.005 0.000 0.005 0.000 {chr}
1 0.000 0.000 0.000 0.000 {fcntl.ioctl}
289 0.005 0.000 0.005 0.000 {getattr}
16 0.001 0.000 0.001 0.000 {hasattr}
646 0.006 0.000 0.006 0.000 {isinstance}
36/24 0.001 0.000 0.009 0.000 {issubclass}
770/767 0.004 0.000 0.004 0.000 {len}
12 0.000 0.000 0.000 0.000 {method '__subclasses__' of 'type' objects}
12 0.000 0.000 0.000 0.000 {method '__subclasshook__' of 'object' objects}
92 0.001 0.000 0.001 0.000 {method 'add' of 'set' objects}
5219 0.024 0.000 0.024 0.000 {method 'append' of 'list' objects}
166 0.002 0.000 0.002 0.000 {method 'cast' of 'CompiledFFI' objects}
6 0.000 0.000 0.000 0.000 {method 'cleanup' of 'ImagingDecoder' objects}
2 0.000 0.000 0.000 0.000 {method 'clear' of 'dict' objects}
5 0.000 0.000 0.000 0.000 {method 'copy' of 'dict' objects}
6 0.003 0.000 0.003 0.000 {method 'decode' of 'ImagingDecoder' objects}
13 0.001 0.000 0.001 0.000 {method 'decode' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
15 0.001 0.000 0.001 0.000 {method 'draw_bitmap' of 'ImagingDraw' objects}
10 0.010 0.001 0.010 0.001 {method 'draw_ellipse' of 'ImagingDraw' objects}
70 0.001 0.000 0.001 0.000 {method 'draw_ink' of 'ImagingDraw' objects}
10 0.000 0.000 0.000 0.000 {method 'draw_lines' of 'ImagingDraw' objects}
10 0.001 0.000 0.001 0.000 {method 'draw_polygon' of 'ImagingDraw' objects}
20 0.001 0.000 0.001 0.000 {method 'draw_rectangle' of 'ImagingDraw' objects}
1 0.000 0.000 0.004 0.004 {method 'encode' of 'unicode' objects}
4 0.000 0.000 0.000 0.000 {method 'endswith' of 'str' objects}
5 0.000 0.000 0.000 0.000 {method 'find' of 'bytearray' objects}
18 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects}
15 0.002 0.000 0.002 0.000 {method 'getmask' of 'ImagingFont' objects}
1 0.000 0.000 0.000 0.000 {method 'index' of 'str' objects}
16 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects}
3 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'keys' of 'dict' objects}
12 0.000 0.000 0.000 0.000 {method 'lower' of 'str' objects}
12 0.000 0.000 0.000 0.000 {method 'match' of '_sre.SRE_Pattern' objects}
166 0.004 0.000 0.004 0.000 {method 'new' of 'CompiledFFI' objects}
16 0.000 0.000 0.000 0.000 {method 'pixel_access' of 'ImagingCore' objects}
6 0.000 0.000 0.000 0.000 {method 'pop' of 'dict' objects}
54 0.001 0.000 0.001 0.000 {method 'read' of '_io.BytesIO' objects}
18 0.000 0.000 0.000 0.000 {method 'readline' of '_io.BytesIO' objects}
12 0.000 0.000 0.000 0.000 {method 'remove' of 'set' objects}
3 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects}
18 0.000 0.000 0.000 0.000 {method 'seek' of '_io.BytesIO' objects}
6 0.000 0.000 0.000 0.000 {method 'setimage' of 'ImagingDecoder' objects}
1 0.000 0.000 0.000 0.000 {method 'setter' of 'property' objects}
7 0.000 0.000 0.001 0.000 {method 'sort' of 'list' objects}
11 0.000 0.000 0.000 0.000 {method 'split' of 'str' objects}
7 0.000 0.000 0.000 0.000 {method 'startswith' of 'str' objects}
12 0.000 0.000 0.000 0.000 {method 'tell' of '_io.BytesIO' objects}
4 0.000 0.000 0.000 0.000 {method 'translate' of 'str' objects}
30 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}
18 0.000 0.000 0.000 0.000 {min}
28 0.000 0.000 0.000 0.000 {ord}
1 0.000 0.000 0.000 0.000 {posix.open}
2 0.000 0.000 0.000 0.000 {posix.stat}
2 0.000 0.000 0.000 0.000 {range}
1 0.000 0.000 0.000 0.000 {sorted}
real 0m2.961s
user 0m1.900s
sys 0m0.280s
From what I can see the 5 0.427 0.085 1.114 0.223 device.py:181(display)
and the 166 0.523 0.003 0.523 0.003 {built-in method i2c_smbus_access}
seems to be the big offenders.
As I can see every loop the whole image is sent to the OLED. I'm wondering if would be beneficial to keep the previous image in memory, perform some image logic operations (XOR?!) and send only the "delta" to the OLED. This way, if only a small portion of the "image" changes, only those pixels, or "pages" will get updated over I2C.
I'll see if I find some time to play with the Pillow tool and have a look on the datasheets to see if that's possible.
from luma.oled.
That definitely seems like a good idea. As far as I remember you can access individual pages and pixels on the device.
I'm away for a couple of weeks, so will look into it a bit more in september, but by all means go for it yourself & if I can help I will.
from luma.oled.
Just an update... I got some reasonable performance improvement. The easiest one is to increase the I2C Baudrate on the RPI. To do that just add the following to the /boot/config.txt and restart (assuming you're using a recent version of Raspbian):
dtparam=i2c_arm=on
dtparam=i2c1_baudrate=400000
That's 400Khz, compared to the default 100Khz. I've tried to push to 1Mhz, it still works but there is no much performance gain and too fast might cause communication issues as not all I2C devices support 1Mhz.
The other change is to the code itself, I'll try to get a version to send here but I basically start using numpy
library which boost the conversion from Image to array.
I also started printing things by "page", that's actually "lines of 8 bits". I've done some tests printing 8x8 pixels but after many attempts I noticed that there is too much overhead just to put the cursor on the right position and the profiler start to show some delays.
The idea is basically to compare the previous image (numpy array) with the new one and "print" only the modified lines. If you just change one or two lines, things are really fast!
The test code below is basically displaying 10 images in 0.8s (after loading all libs) on my RPI B+. The optimization prints only 60 lines instead of printing 80 lines (each image has 8 lines of 8 pixels each), that's the "delta per line".
Be aware that you'll need numpy
to use it... I compile myself as I don't use the stock Python and it takes more than one hours on RPI.
import smbus
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import time
import cProfile, pstats, StringIO
pr = cProfile.Profile()
lookup = np.array([
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
])
port = 1
addr = 0x3C
cmd_reg = 0x00
data_reg = 0x40
bus = smbus.SMBus(port)
# Set page number
setPageCounter = 0
def setPage(page, endPage=0):
# write CMD
cmd = [0x22, page, page + endPage]
bus.write_i2c_block_data(addr, cmd_reg, cmd)
global setPageCounter
setPageCounter += 1
# Set Start and End column number.
setColCounter = 0
def setCol(col, endCol=127):
# write CMD
cmd = [0x21, col, col + endCol]
bus.write_i2c_block_data(addr, cmd_reg, cmd)
global setColCounter
setColCounter += 1
# write DATA
writeCounter = 0
def writeData(data):
global writeCounter
for x in np.nditer(data, op_flags=['readwrite']):
x[...] = lookup[x]
data = data.flatten().tolist()
for i in xrange(0, len(data), 32):
bus.write_i2c_block_data(addr, data_reg, data[i:i+32])
writeCounter += 1
def draw(shape):
im = Image.new('L', (128, 64))
dr = ImageDraw.Draw(im)
if shape == 0:
pass
#blank image
if shape == 1:
dr.rectangle((0, 0, 120, 30), outline=0, fill=1)
if shape == 2:
dr = ImageDraw.Draw(im)
font = ImageFont.truetype('pixelmix.ttf', 8)
dr.text((50, 50), time.strftime("%X"), font=font, fill=1)
return np.asarray(im)
def printOled(current_data, new_data):
i = 0
write_page = None
last_page = 7
for row in new_data:
if not np.array_equal(current_data[0], row):
# We only set a new page if necessary. If it's a continuous write the page should increment itself.
if write_page != i:
setPage(i, last_page)
write_page = i
writeData(row)
write_page += 1
i += 1
def test(a, b):
da = np.packbits(a, axis=0)
db = np.packbits(b, axis=0)
diff = np.not_equal(a,b)
# Create a blank Image... that actually can be a first image, we just need something to compare with.
data_blank = np.packbits(draw(0), axis=0)
setCol(0)
pr.enable()
for i in range(0,5):
a = draw(1)
data_a = np.packbits(a, axis=0)
printOled(data_blank, data_a)
b = draw(2)
data_b = np.packbits(b, axis=0)
printOled(data_a, data_b)
# time.sleep(1);
#print 'Build a matrix of 8x8 bits. Lines X Columns'
#matrix = np.asarray(np.split(np.asarray(np.split(a, 2, axis=1)), 2, axis=1))
pr.disable()
s = StringIO.StringIO()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
print 'SetPages: {} SetCols: {} Writes: {}'.format(setPageCounter, setColCounter, writeCounter)
from luma.oled.
As you can see with numpy
you can load the Image directly into the array... and also it has some very funky, but it doesn't require many changes apart from the bit order change using the lookup. One thing important to high light and I spent quite some time on is that numpy
only accepts a 8bit image... if you try to load an 1bit image on it, the produce array is broken. In any case it still much faster than using the Image.getdata()
Cheers!
from luma.oled.
Another update... I just got my RPi 2 and the same code which used to take 0.8s now takes 0.34s. I haven't recompiled anything, just plugged the SD card on the new RPi and was working!
The RPi 2 is really much faster! I'm running CAN Bus sending 1.3K msg/s + one ssd1306 refresh per second + RabbitMq and the system is around 92% IDLE....you can even notice on the SSH session that is more responsive and the tasks get well distributed across the 4 cores.
Well done Raspberry Pi team!
from luma.oled.
Hi, yeah the RPi2 is a lot faster: also the class of microSD card makes a big difference too - try class 10. I haven't really had chance to digest your earlier comments (even thoufh I've been back off hols for a few weeks now) - is there worth pulling anything out into the code to make it quicker?
I think when I wrote it originally, I assumed that as the screen is so small, keeping track of dirty writes and doing diffs would be more effort (both dev and CPU time) than just flushing everything to the screen. I willl have a fresh look into the profiling trace you attached.
from luma.oled.
You can do a very simple thing that is use the numpy library, so you do
need to loop through the whole image array.
On 19 September 2015 at 00:30, Richard Hull [email protected]
wrote:
Hi, yeah the RPi2 is a lot faster: also the class of microSD card makes a
big difference too - try class 10. I haven't really had chance to digest
your earlier comments (even thoufh I've been back off hols for a few weeks
now) - is there worth pulling anything out into the code to make it quicker?I think when I wrote it originally, I assumed that as the screen is so
small, keeping track of dirty writes and doing diffs would be more effort
(both dev and CPU time) than just flushing everything to the screen. I
willl have a fresh look into the profiling trace you attached.—
Reply to this email directly or view it on GitHub
#8 (comment).
from luma.oled.
@musskopf optional support for numpy would be cool (if it makes things faster?)
from luma.oled.
I dont really want to add numpy as a dependency.
Adding the following kernel params to /boot/config.txt makes an appreciable difference like @musskopf noted:
dtparam=i2c_arm=on
dtparam=i2c1_baudrate=400000
Today, I revisited the cProfile trace, and have pushed a new version (f82e1d3) which aggressively optimises the display
method; it reduces the render time by a factor or two - down from ~63ms to about ~33ms (as measured on my RPi Zero, running at 800MHz).
I've only done the ssd1306 version at the moment and not the sh1106 driver - mainly because I dont have one of those. Need to implement some tests (see #33) before tackling that I think.
... In the meantime, I think this ticket should be closed & for any new perf-related issues/queries, please raise a new issue.
from luma.oled.
Related Issues (20)
- how do i change in code sh1106 driver , need location for code change ? HOT 2
- [question] access screens on remote Pi?
- Support for non-Raspberry Pi Linux boards HOT 1
- New Haven 2.7 oled with ssd1322 HOT 4
- ImportError: The _imagingft C module is not installed HOT 1
- White display SPI issue with 6.x kernels HOT 2
- Array is incorrectly shifted for 96x16 OLEDs. HOT 5
- Scrolling text within bounding box
- Input/output error for luma.oled HOT 5
- sys_info.py: error: I2C device not found on address: 0x3C.But i2c can detected on pi 4b arm64
- Low FPS on SSD1322 and Raspberry Pi 3B HOT 1
- Orange Pi zero2 error Timer expired HOT 2
- Wrong column offset 1.54" SH1106 I2C HOT 5
- Hardware Accelerated 3D on the SSD1306
- from oled.device import ssd1306, sh1106 ModuleNotFoundError: No module named 'oled' HOT 7
- ImportError: cannot import name 'sh1107' from 'luma.oled.device' HOT 1
- Incremental screen updates with Luma and SH1106? HOT 1
- Semi-random pixels on SSD1322 - how to fix? HOT 4
- RPi3B multiple SPI SSD1306 displays HOT 5
- Support to display latin characters HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from luma.oled.