LINUX.ORG.RU

Как ускорить опрос файлов?

 , , ,


0

1

Пишу программу работающую с GPIO посредством файловой системы. Сейчас испытываю её на самописном эмуляторе GPIO файлов. Обнаружил что опрос всех 26 файлов занимает минимум 0,04 секунды. Это нормально или слишком много?

Запрашиваю состояние следующим кодом:

Public Sub Main()
  ' Автомойка
  Dim tb, te As Float
  Dim Box1 As New BoxType
  Dim cGPIO As New ControlGPIO
  Dim TestBin As New Boolean[]
  Dim a As Integer, m As Integer
  
  LoadConfig ' Загрузка настроек
  tb = Timer
  cGPIO.ConfGPIO("/home/stas/virtual_gpio/", "/opt/write-string-to-file", 26)
  
  te = Timer

  TestBin = cGPIO.GetStatusGPIO()
  m = TestBin.Max
  For a = 1 To m
    If TestBin[a] = True Then Print "GPIO" & LTrim(Str(a)) & " = True"
  Next
  
  Print "Время " & Str(Timer - te)
  
End

На выходе получаю:

GPIO3 = True
Время 0,04341006278992

Ниже код класса.

' Gambas class file ControlGPIO

Public GPIOpath As String  ' В конце строки должен обязательно быть слэш
Public PathScriptGPIO As String  ' Скрипт для ввода значений в GPIO порт
Public MaxGPIO As Integer ' Сколько всего GPIO

Public DisabledReadGPIO As New Boolean[] ' Включает игнорирование данных GPIO при чтении
Public SubstitutionValueGPIO As New Boolean[] ' При отключенном чтении, возвращает значение из данного массива
Public DisabledWriteGPIO As New Boolean[] ' Включает игнорирование данных GPIO при записи. Воздействует на функцию WriteGPIO
' Данные ограничения и массив подмены не работают при сипользовании функции ReadGPIO напрямую
' Поэтому следует запрашивать данные через GetStatusGPIO с особыми параметрами


Public Function GetStatusGPIO() As Boolean[]
  ' Функция возвращает двоичный массив содержащий состояние GPIO входов

  Dim Result As New Boolean[]
  Dim a As Integer, m As Integer
  Dim r As Boolean
  Dim ResultRealRead As Boolean
  Dim t As Integer, i As Integer
  
  Result.Add(False) ' Нулевой элемент массива
  
 'обычное считывание
  For a = 1 To MaxGPIO
    r = False ' Флаг подмены
    If DisabledReadGPIO.Count > 0 Then
      ' Если есть запреты на реальное чтение
      If DisabledReadGPIO.Max <= a Then
        ' Если входит в зону запрета
        If DisabledReadGPIO[a] = True Then
          ' Запрет на реальное чтение
          ' Подмена
          If SubstitutionValueGPIO.Count > 0 Then
            'Есть подмены
            If SubstitutionValueGPIO.Max >= a Then
              'Подмена определена 
              r = True ' Совершить подмену
            Endif
          Endif
        Endif
      Endif
    Endif
      
    If r = True Then
      ' Подмена
      If a > Result.Max Then
        Result.Add(SubstitutionValueGPIO[a]) 'Добавление подменного результата
      Else
        Result[a] = SubstitutionValueGPIO[a] 'Замена образца на подменный результат
      Endif
    Else
      ' Реальное чтение
      ResultRealRead = ReadGPIO(a)
      If a > Result.Max Then
        Result.Add(ResultRealRead) 'Добавление прочитанного результата
      Else
        Result[a] = ResultRealRead 'Замена образца на прочитанный результат
      Endif
    Endif
  Next
  Return Result
End



Public Sub ConfGPIO(PathGPIO As String, ScriptWriteGPIO As String, MaxPortsGPIO As Integer)
  PathScriptGPIO = ScriptWriteGPIO
  MaxGPIO = MaxPortsGPIO
  
  If Len(PathGPIO) > 0 Then
    If Mid(PathGPIO, Len(PathGPIO), 1) = "/" Then
      GPIOpath = PathGPIO
    Else  
      GPIOpath = PathGPIO & "/" ' Добавляет в конце / слэш если он не передан
    Endif
      
  Endif
End




Public Function ReadGPIO(GPIOn As Integer) As Boolean
  Dim P As Process
  Dim t As String
  Dim t1 As String 
  Dim r As Boolean
  Dim s As String
  s = GPIOpath & "gpio" & LTrim(Str(GPIOn)) & "/value"
  Exec ["cat", s] To t
  If Len(t) > 0 Then
    t1 = Mid(t, 1, 1)
    If t1 = "1" Then r = True
  Endif
  Return r
End

Public Sub WriteGPIO(GPIOn As Integer, Value As Boolean)
  Dim s As String
  Dim t As String
  s = GPIOpath & "gpio" & LTrim(Str(GPIOn)) & "/value"
  If Value = True Then
    ' Ввод единицы
    Exec [PathScriptGPIO, "1", s] To t
  Else
    ' Ввод нуля
    Exec [PathScriptGPIO, "0", s] To t
  Endif
  'Print s
End

Public Sub Execute(IntegerArrayGPIO As Integer[])
  ' Функция выполняет команды записанные в виде целых чисел.
  ' Модуль числа определяет номер GPIO, а знак определяет значение.
  ' <0 False
  ' >0 True
  Dim a As Integer, m As Integer
  If IntegerArrayGPIO.Count > 0 Then
    'Если в массиве есть элементы
    m = IntegerArrayGPIO.Max
    For a = 0 To m
      If IntegerArrayGPIO[a] > 0 Then
        ' True
        WriteGPIO(Abs(IntegerArrayGPIO[a]), True) ' Функция Abs использована в данной строе для единообразия
      Endif
      If IntegerArrayGPIO[a] > 0 Then
        ' False
        WriteGPIO(Abs(IntegerArrayGPIO[a]), False)
      Endif
      ' Значение 0 игнорируется
    Next
  Endif
  
End

/opt/write-string-to-file

#!/bin/bash
echo "$1" > "$2" 2>/dev/null
exit 0

Public Sub

О боги! Чую, весело будет :-)

If DisabledReadGPIO.Count > 0 Then
      ' Если есть запреты на реальное чтение
      If DisabledReadGPIO.Max <= a Then
        ' Если входит в зону запрета
        If DisabledReadGPIO[a] = True Then
          ' Запрет на реальное чтение
          ' Подмена
          If SubstitutionValueGPIO.Count > 0 Then
            'Есть подмены
            If SubstitutionValueGPIO.Max >= a Then
              'Подмена определена 
              r = True ' Совершить подмену
            Endif
          Endif
        Endif

В basic-и не завезли что-то типа HashMap? Впрочем, это я так, придираюсь. Самое веселое-то дальше.

Exec ["cat", s] To t
Exec [PathScriptGPIO, "1", s] To t

Зачем? Можно же воспользоваться, собственно, чтением как текстового файла и не иметь накладных расходов на ввод-вывод.

з.ы. а мне ещё было стыдно за мою qt-ю пивоварню. Впрочем, это совсем другая история.

alex4321
()
Ответ на: комментарий от Rastafarra

Ты так говоришь, будто бэйсики на linux не завезли (gambas небось). Да и вроде самое интересное дальше.

alex4321
()
Ответ на: комментарий от alex4321

Точнее - на перенаправление. Не знаю каковы они вообще и в конкретной обёртке, но здесь-то они вообще ни к чему.

alex4321
()
Ответ на: комментарий от alex4321

Зачем? Можно же воспользоваться, собственно, чтением как текстового файла и не иметь накладных расходов на ввод-вывод.

хм.. У меня когда то давно были глюки связанные с чтением fifo потока как обычного файла. Поэтому и завернул всё в эту обёртку. Что то я сразу не понял где узкое место. Спасибо.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

С этого момента поподробнее бы. А то делал с год назад я одну крестоподелку без проблем.

Да и, собственно, cat же читает его «обычным» образом, не? Если так (сейчас лень читать исходники) - то остаётся разве что проблема в gambas-е.

alex4321
()
Ответ на: комментарий от rezedent12

А зря. Собственно, тогда бы требовалось что-то типа (далее сиподобный псевдокод) :

bool locked = lockedMap.containsKey(pin) && lockedMap[pin]

Ну а с каким-нибудь set-м (кстати, вроде же есть в vb, который gambas косплеит) :

bool locked = lockedSet.contains(pin)

alex4321
()
Ответ на: комментарий от alex4321

Да и на массивах можно подобное изобразить. Какой-нибудь

EState[] state
Где
enum EState { E_NORMAL, E_LOCKED; }

Ну и соответственно - если

state[pin] == E_NORMAL
, то читаем, если
state[pin]==E_LOCKED
- нет.

Только надо вкурить, гарантируется ли инициализация массива E_NORMAL-ми в таком случае - а то код будет длиннее чем с map-м.

alex4321
()
Ответ на: комментарий от alex4321

С этого момента поподробнее бы. А то делал с год назад я одну крестоподелку без проблем.

Это специфическая проблема gambas, он открывает поток и ждёт. Можно конечно открыть его не как файл, а как stream, но это уже не универсально. Я протестирую прямое чтение файла на raspbery pi

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от alex4321

Оффтоп, конечно, но почему gambas-то?

Я его знаю лучше чем другие языки программирования. На нём разработка и что ещё более важно отладка, для меня быстрее.

rezedent12 ☆☆☆
() автор топика

минимум 0,04 секунды. Это нормально или слишком много?

Судя по интернету, на Raspberry Pi 2 можно дёргать GPIO с частотой до 42 МГц. Вот и прикинь, нормально это или нет.

Ты какой-то странный способ работы с GPIO выбрал. Вариант с mmap'ом и быстрее, и в то же время для тестов годится. Просто мапишь другой файл, в который потом пишешь.

i-rinat ★★★★★
()
Ответ на: комментарий от anonymous

Ну я вот совсем не гений, а немного крестов с кутями и qml осилил. Вот хотя бы таких проблем не поимел :-)

Впрочем, дело светоча.

alex4321
()
Ответ на: комментарий от i-rinat

Просто мапишь другой файл, в который потом пишешь.

А это точно можно сделать для /sys/class/gpio/gpio4/value ?

Судя по интернету, на Raspberry Pi 2 можно дёргать GPIO с частотой до 42 МГц. Вот и прикинь, нормально это или нет.

Это в какой операционной системе?

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

А это точно можно сделать для /sys/class/gpio/gpio4/value ?

Конечно нельзя. Это же псевдофайлы, их нельзя мапить. Для них определены только операции чтения и записи. Туда удобно писать из скриптов. Но если нужно работать быстро и с минимальными задержками, лучше работать напрямую.

GPIO в малинке, как и в других аналогичных железках, отображаются в физические адреса памяти. Пишешь туда значение — GPIO пин поднимается или опускается. Так же и в обратную сторону — нужно просто читать память. Для доступа к физическим адресам просто мапишь /dev/mem по определённому смещению к себе в адресное пространство, и вперёд.

Это в какой операционной системе?

А какая разница-то? Под Linux это, не на голом железе.

http://codeandlife.com/2015/03/25/raspberry-pi-2-vs-1-gpio-benchmark/

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

GPIO в малинке, как и в других аналогичных железках, отображаются в физические адреса памяти. Пишешь туда значение — GPIO пин поднимается или опускается. Так же и в обратную сторону — нужно просто читать память. Для доступа к физическим адресам просто мапишь /dev/mem по определённому смещению к себе в адресное пространство, и вперёд.

Ты зачем плохое человеку советуешь?

Deleted
()

опрос всех 26 файлов занимает минимум 0,04 секунды. Это нормально или слишком много?

По мне, так это СЛИШКОМ много. По UART'у на скорости 9600 бод то же самое количество информации можно передать в 12 раз быстрее, Карл.

anonymous
()
Ответ на: комментарий от i-rinat

А что хорошее для GPIO?

/sys/class/gpio конечно же. Там ещё и poll() можно делать, если чип умеет прерывания на GPIO и в ядре это реализовано.

Для того, чтобы делать что-то с GPIO из юзерспейса в обход ядра, нужны очень веские основания, которых у ТСа нет.

Deleted
()

По теме:

  • Ты тестируешь на реальных файлах, а не на псевдофайлах в /sys. В raspberry pi говно не только вместо процессора, но и вместо жёсткого диска. Да, microSD тормозят всегда и очень сильно. Попробуй tmpfs.
  • У тебя basic. Он не только говно в качестве ЯП, но ещё и все известные его реализации тормозят.
  • У тебя не тест производительности, а говно. Скорее всего измеренное время выполнения меньше, чем погрешность измерения. Попробуй увеличить количество итераций так, чтобы измеренное время было в районе десятков секунд.
  • Нормальное или нет ты получишь время в результате теста - судить исключительно тебе исходя из твоих задач.
Deleted
()
Ответ на: комментарий от Deleted

Ты тестируешь на реальных файлах, а не на псевдофайлах в /sys. В raspberry pi говно не только вместо процессора, но и вместо жёсткого диска. Да, microSD тормозят всегда и очень сильно. Попробуй tmpfs.

Я тестировал на настольном ПК. На малинке ещё не пробовал.

У тебя не тест производительности, а говно. Скорее всего измеренное время выполнения меньше, чем погрешность измерения. Попробуй увеличить количество итераций так, чтобы измеренное время было в районе десятков секунд.

Я делал несколько тестов, погрешность измерения в районе мелких числел с мантисой.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

Я тестировал на настольном ПК. На малинке ещё не пробовал.

tmpfs

Я делал несколько тестов, погрешность измерения в районе мелких числел с мантисой.

Откуда инфа?

Deleted
()
Ответ на: комментарий от Deleted

Я делал несколько тестов, погрешность измерения в районе мелких числел с мантисой.

Откуда инфа?

Я ещё тестировал фиктивное чтение.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от alex4321

Кстати, ты от перенаправления консольных утилит попробовал отказаться? Насколько заметен эффект?

Ещё не сделал. Я сейчас другую функцию пишу.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от i-rinat

Ты не различаешь случайную и систематическую погрешности?

Я то различаю, но поясни на всякий случай. Вдруг мы о разном думаем.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

Неа, я не буду писать.

Вдруг кто-то потом подумает, что ты не знал и не знаешь, и так пытаешься информацию из меня вытянуть. Неудобно получится.

i-rinat ★★★★★
()
Ответ на: комментарий от Deleted

В raspberry pi говно не только вместо процессора, но и вместо жёсткого диска

У тебя basic. Он не только говно в качестве ЯП

У тебя не тест производительности, а говно

Сильно :]

intelfx ★★★★★
()
Ответ на: комментарий от i-rinat

Вдруг кто-то потом подумает, что ты не знал и не знаешь, и так пытаешься информацию из меня вытянуть. Неудобно получится.

Максимальная разница при «прогретом кэше» и других задачах составляла не более 3 тысячных секунды.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от i-rinat

В данном случае систематическая погрешность измерения не значима.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от Stil

С наличием перка «googler 80lvl» – можно :p

Не-а. Если прочитаешь и вникнешь, то уже будешь знать. А если просто случайные фразы копипастить, другим сразу видно, что всё невпопад.

i-rinat ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.