Почему несколько операторов печати ускоряются после цикла чтения ввода-вывода? - PullRequest
0 голосов
/ 27 марта 2019

У меня есть устройство I2C, подключенное к Raspberry Pi 3. Устройство I2C хранит 9 сэмплов в своем буфере FIFO на частоте 104 Гц. Я опрашиваю устройство на количество сохраненных образцов. Каждый образец составляет 2 байта. Когда буфер FIFO достигает выборок 2016 года, я считываю все 4032 байта за один раз, выдав 126 32-байтовых считываний данных блока i2c.

Во время чтения устройство все еще заполняет FIFO. Так что, когда я закончу читать все образцы 2016 года, я могу сразу же опросить и увидеть, что есть 630 новых образцов.

Если я распечатаю количество сэмплов в FIFO, тогда время чтения блока будет меньше, чем если бы я не печатал. В этом случае я получаю только 387 новых образцов.

Я не понимаю, как оператор print заставляет мой IO читать быстрее.

Я попытался изменить пороговое значение. Кроме того, перемещение печати внутри оператора if снова замедлило процесс. Печать с промывкой = True ничего не делает, ни до, ни после достижения порогового значения.
Я пытался напечатать несколько фиктивных строк непосредственно перед чтением данных (выше tic ()). Это приводит к тому, что первые несколько операций чтения из буфера будут быстрыми (0,410 с), а затем медленными (0,661 с) для всех после. Количество быстрых чтений увеличивается с увеличением количества операторов печати. ​​

import numpy as np
from time import sleep
from time import time
from smbus2 import SMBus


# Helper timing functions
_tstart_stack = []

def tic():
    _tstart_stack.append(time())

def toc(fmt="Elapsed: %s s"):
    print(fmt % (time() - _tstart_stack.pop()))


# Datasheet: https://www.pololu.com/file/0J1087/LSM6DS33.pdf
# REGISTER DEFINITIONS:
WHO_AM_I = 0x0F  # page 46
WHO_AM_I_VAL = 0b01101001
# FIFO registers
FIFO_STATUS1 = 0x3A  # page 59
FIFO_STATUS2 = 0x3B  # page 60
FIFO_STATUS3 = 0x3C  # page 60
FIFO_STATUS4 = 0x3D  # page 61
FIFO_CTRL1 = 0x06  # page 40
FIFO_CTRL2 = 0x07  # page 40
FIFO_CTRL3 = 0x08  # page 41
FIFO_CTRL4 = 0x09  # page 42
FIFO_CTRL5 = 0x0A  # page 43
FIFO_DATA_OUT_L = 0x3E  # page 61
FIFO_DATA_OUT_H = 0x3F  # page 61
# Control registers
CTRL1_XL = 0x10  # page 46
CTRL2_G = 0x11  # page 48
CTRL3_C = 0x12  # page 49
CTRL4_C = 0x13  # page 50
CTRL5_C = 0x14  # page 50
CTRL6_C = 0x15  # page 51
CTRL7_G = 0x16  # page 52
CTRL8_XL = 0x17  # page 52
CTRL9_XL = 0x18  # page 53
CTRL10_C = 0x19  # page 54
TAP_CFG = 0x58  # page 64
WAKE_UP_DUR = 0x5C  # page 66
# Accelerometer read
OUTX_L_XL = 0x28  # page 58
OUTX_H_XL = 0x29  # page 58
OUTY_L_XL = 0x2A  # page 58
OUTY_H_XL = 0x2B  # page 59
OUTY_L_XL = 0x2C  # page 59
OUTY_H_XL = 0x2D  # page 59
# Gyro read
OUTX_L_G = 0x22  # page 56
OUTX_H_G = 0x23  # page 57
OUTY_L_G = 0x24  # page 57
OUTY_H_G = 0x25  # page 57
OUTY_L_G = 0x26  # page 58
OUTY_H_G = 0x27  # page 58

# BIT DEFINITION MASKS
FIFO_THRESHOLD  = 0b10000000  # FTH in FIFO_STATUS2, 1 when threshold is crossed.
FIFO_OVER_RUN   = 0b01000000  # FIFO FULL + 1 sample
FIFO_FULL       = 0b00100000  # in FIFO_STATUS2, FIFO full on next sample
FIFO_EMPTY      = 0b00010000  # in FIFO_STATUS2


def init(BUS, LSM):
    # LSM6DS33 datasheet, page 46-54
    # 104 Hz (high performance), 2g accelerometer full-scale selection, 50Hz anti-aliasing filter bandwidth selection
    BUS.write_byte_data(LSM, CTRL1_XL,  0b01000011)
    # 104 Hz (high performance), 245 dps (degrees per second), full scale disabled
    BUS.write_byte_data(LSM, CTRL2_G,   0b01000000)
    # BDU enabled, auto increment address on multiple byte access.
    BUS.write_byte_data(LSM, CTRL3_C,   0b01000100)
    # high pass filter gyroscope enabled
    BUS.write_byte_data(LSM, CTRL7_G,   0b01000000)
    # low pass filter accelerometer enabled and xyz gyro enable
    BUS.write_byte_data(LSM, CTRL10_C,  0b00111100)

    # threshold on 2016 samples
    BUS.write_byte_data(LSM, FIFO_CTRL1, 0b11100000)
    # Time stamp enable, FIFO on data ready, threshold on 2016 samples
    BUS.write_byte_data(LSM, FIFO_CTRL2, 0b10000111)
    # No decimation (downsampling) for gyro and acc
    BUS.write_byte_data(LSM, FIFO_CTRL3, 0b00001001)
    # No decimation (downsampling) for timer
    BUS.write_byte_data(LSM, FIFO_CTRL4, 0b00001000)
    # FIFO ODR 104Hz, FIFO continous mode
    BUS.write_byte_data(LSM, FIFO_CTRL5, 0b00100110)

    BUS.write_byte_data(LSM, TAP_CFG,     0b10000000)  # Timer enable
    BUS.write_byte_data(LSM, WAKE_UP_DUR, 0b00000000)  # Timer resolution 6.4ms


def who_am_i(BUS, LSM):
    # whoami identification
    return BUS.read_byte_data(LSM, WHO_AM_I) == WHO_AM_I_VAL


def wait_data_ready(BUS, LSM):
    # Check Accelerometer Data Ready
    while True:  # while data not ready
        status = BUS.read_byte_data(LSM, 0x1E)
        if status & 0x01 == 1:
            return 1


def reset_timer(BUS, LSM):
    BUS.write_byte_data(LSM, 0x42, 0xAA)  # TIMESTAMP2_REG Write 0xAA to reset.


def reset_fifo(BUS, LSM):
    current_settings = BUS.read_byte_data(LSM, FIFO_CTRL5)
    bypassmode = 0b01111000 & current_settings
    BUS.write_byte_data(LSM, FIFO_CTRL5, bypassmode)  # FIFO bypass mode
    sleep(0.1)
    BUS.write_byte_data(LSM, FIFO_CTRL5, current_settings)  # Back to normal


def read_fifo(BUS, LSM):
    while 1:
        data = []
        # Read the two FIFO STATUS registers, addr is device I2C address
        status_regs = BUS.read_i2c_block_data(LSM, FIFO_STATUS1, 2)

        # Get the current number of samples in FIFO queue
        if FIFO_FULL & status_regs[1]:
            n_samp = 4095
        else:
            n_samp = (status_regs[1] & 0b00001111)*256 + status_regs[0]

        if FIFO_EMPTY & status_regs[1]:
            print("FIFO EMPTY!")

        # THIS PRINT STATEMENT SPEEDS UP THE FOR LOOP BELOW
        # print("number of samples ", n_samp)

        if FIFO_THRESHOLD & status_regs[1]:
            tic()
            # Threshold: 2016 samples=4032bytes=126 reads of 32 bytes
            for _ in range(126):
                data.extend(BUS.read_i2c_block_data(LSM, FIFO_DATA_OUT_L, 32))
            toc()

            status_regs = BUS.read_i2c_block_data(LSM, FIFO_STATUS1, 2)
            n_samp = (status_regs[1] & 0b00001111)*256 + status_regs[0]
            print("number of samples after read", n_samp)


if __name__ == "__main__":
    # I2C bus and register
    BUS = SMBus(1)
    LSM = 0x6b  # 3-axis gyroscope and 3-axis accelerometer

    print("Whoami: ", who_am_i(BUS, LSM))
    init(BUS, LSM)
    reset_fifo(BUS, LSM)
    reset_timer(BUS, LSM)
    read_fifo(BUS, LSM)

С оператором печати я получаю:
прошедшее время: 0,410 с
количество образцов после чтения: 387

Без утверждения print я получаю:
прошедшее время: 0,661 с
количество образцов после прочтения: 621

Я ожидал, что удаление отпечатка ускорит процесс, а не замедлит его. Я сбрасываю FIFO при первом запуске, поэтому программа всегда сначала печатает «FIFO EMPTY».

Редактировать: Включено достаточно кода для автономной работы. Проблема в функции read_fifo (BUS, LSM). Я работаю на Python 3.4.2 и использую модуль smbus2: https://pypi.org/project/smbus2/

...