Code Monkey home page Code Monkey logo

Comments (10)

rm-hull avatar rm-hull commented on May 23, 2024

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.

musskopf avatar musskopf commented on May 23, 2024

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.

rm-hull avatar rm-hull commented on May 23, 2024

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.

musskopf avatar musskopf commented on May 23, 2024

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.

musskopf avatar musskopf commented on May 23, 2024

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.

musskopf avatar musskopf commented on May 23, 2024

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.

rm-hull avatar rm-hull commented on May 23, 2024

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.

musskopf avatar musskopf commented on May 23, 2024

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.

thijstriemstra avatar thijstriemstra commented on May 23, 2024

@musskopf optional support for numpy would be cool (if it makes things faster?)

from luma.oled.

rm-hull avatar rm-hull commented on May 23, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.