[PYTHON] Gerätetreiber (NumPy-kompatibel) für Programme und Hardware, die unter Linux im Benutzerbereich ausgeführt werden, um Speicher gemeinsam zu nutzen

Einführung

[Udmabuf](https: :), eingeführt im vorherigen Beitrag ["Gerätetreiber für Programme und Hardware, die unter Linux im Benutzerbereich ausgeführt werden, um Speicher freizugeben" (http://qiita.com/ikwzm/items/cc1bb33ff43a491440ea) //github.com/ikwzm/udmabuf) ist jetzt in NumPy (Pythons numerische Berechnungsbibliothek) verfügbar. Insbesondere wird der von udmabuf im Kernel zugewiesene Pufferbereich von NumPys memmap und ndarray zugeordnet In diesem Artikel werde ich erklären, wie es geht.

udmabuf Update

Wenn die Version von udmabuf Version 0.5.0 (24.04.2016) oder früher ist, wird leider der folgende Fehler angezeigt.

shell# python
Python 2.7.9 (default, Aug 13 2016, 17:56:53)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> m = np.memmap('/dev/udmabuf0', dtype=np.uint8, mode='r+', shape=(100))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/numpy/core/memmap.py", line 217, in __new__
    fid.seek(0, 2)
IOError: [Errno 29] Illegal seek

Dies liegt daran, dass udmabuf lseek nicht unterstützt hat. Anscheinend verwendet NumPys Memmap seek (0,2), um die Größe der Datei zu ermitteln, aber ich habe vergessen, lseek () in udmabuf zu implementieren. udmabuf Version 0.6.0 (29.01.2017) unterstützt lseek. Wenn Sie also udmabuf mit NumPy verwenden möchten, verwenden Sie bitte umdabuf Version 0.6.0 oder höher.

Anwendungsbeispiel

Installieren Sie udmabuf

Installieren Sie zuerst udmabuf. Informationen zur spezifischen Methode finden Sie unter ["Gerätetreiber für Programme und Hardware, die unter Linux im Benutzerbereich ausgeführt werden, um Speicher freizugeben" (http://qiita.com/ikwzm/items/cc1bb33ff43a491440ea).

Im folgenden Beispiel wird udmabuf.ko direkt mit insmod installiert. Zu diesem Zeitpunkt ist ein Puffer von 8 MByte als udmabuf0 gesichert.

shell# insmod udmabuf.ko udmabuf0=8388608
[34654.590294] alloc_contig_range: [1f100, 1f900) PFNs busy
[34654.596154] alloc_contig_range: [1f200, 1fa00) PFNs busy
[34654.622746] udmabuf udmabuf0: driver installed
[34654.627153] udmabuf udmabuf0: major number   = 237
[34654.631889] udmabuf udmabuf0: minor number   = 0
[34654.636685] udmabuf udmabuf0: phys address   = 0x1f300000
[34654.642002] udmabuf udmabuf0: buffer size    = 8388608

udmabuf_test.py

Hier ist ein Skript, das einen einfachen Test mit Python + NumPy durchführt.

udmabuf_test.py


import numpy as np
import time

class Udmabuf:
    """A simple udmabuf class"""

    def __init__(self, name):
        self.name        = name
        self.device_name = '/dev/%s'               % self.name
        self.class_path  = '/sys/class/udmabuf/%s' % self.name
        for line in open(self.class_path + '/size'):
            self.buf_size = int(line)
            break

    def memmap(self, dtype, shape):
        self.item_size = np.dtype(dtype).itemsize
        self.mem_map   = np.memmap(self.device_name, dtype=dtype, mode='r+', shape=shape)

def test_1(a):
    for i in range (0,9):
        a *= 0
        a += 0x31

if __name__ == '__main__':
    udmabuf      = Udmabuf('udmabuf0')
    test_dtype   = np.uint8
    test_size    = int(udmabuf.buf_size/(np.dtype(test_dtype).itemsize))
    udmabuf.memmap(dtype=test_dtype, shape=(test_size))
    comparison   = np.zeros(test_size, dtype=test_dtype)
    print ("test_size  : %d" % test_size)
    start        = time.time()
    test_1(udmabuf.mem_map)
    elapsed_time = time.time() - start
    print ("udmabuf0   : elapsed_time:{0}".format(elapsed_time) + "[sec]")
    start        = time.time()
    test_1(comparison)
    elapsed_time = time.time() - start
    print ("comparison : elapsed_time:{0}".format(elapsed_time) + "[sec]")
    if np.array_equal(udmabuf.mem_map, comparison):
        print ("udmabuf0 == comparison : OK")
    else:
        print ("udmabuf0 != comparison : NG")
    

Im obigen Skript wird der von udmabuf im Kernel zugewiesene Pufferbereich von numpy.memmap aus Python zur Verfügung gestellt. Von numpy.memmap erstellte Objekte können auf die gleiche Weise wie numpy.ndarray betrieben werden. Im obigen Skript werden a * = 0 und a + = 0x31 zehnmal wiederholt, um die Ausführungszeit zu messen.

Ausführungsergebnis

Als ich das Skript im vorherigen Abschnitt ausgeführt habe, habe ich das folgende Ergebnis erhalten.

shell# python udmabuf_test.py
test_size  : 8388608
udmabuf0   : elapsed_time:1.53304982185[sec]
comparison : elapsed_time:1.536673069[sec]
udmabuf0 == comparison : OK

Die Ausführungszeit für die Operation auf udmabuf0 (im Kernel zugewiesener Pufferbereich) und die Ausführungszeit für dieselbe Operation auf ndarray (Vergleich) waren nahezu gleich. Mit anderen Worten, bei udmabuf0 scheint der CPU-Cache auch effektiv zu funktionieren.

Nachdem ich dieses Skript ausgeführt hatte, überprüfte ich den Inhalt von udmabuf0.

shell# dd if=/dev/udmabuf0 of=udmabuf0.bin bs=8388608
1+0 records in
1+0 records out
8388608 bytes (8.4 MB) copied, 0.151531 s, 55.4 MB/s
shell# 
shell# od -t x1 udmabuf0.bin
0000000 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
*
40000000

Nach dem Ausführen des Skripts konnte ich bestätigen, dass das Ausführungsergebnis im Puffer verbleibt. Stellen Sie für alle Fälle sicher, dass Sie es mit NumPy lesen können.

shell# python
Python 2.7.9 (default, Aug 13 2016, 17:56:53)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> a = np.memmap('/dev/udmabuf0', dtype=np.uint8, mode='r+', shape=(8388608))
>>> a
memmap([49, 49, 49, ..., 49, 49, 49], dtype=uint8)
>>> a.itemsize
1
>>> a.size
8388608
>>>

Zusammenfassung

Sie können jetzt Pythons NumPy verwenden, um den im Kernel zugewiesenen Pufferbereich mit udmabuf zu bearbeiten. Dies ermöglicht es, den PL-Teil (Programmable Logic) von FPGA direkt mit Python allein zu verarbeiten, ohne in C geschriebenen Code oder Bibliotheken zu verwenden.

Wenn der PL-Teil (Programmable Logic) des FPGA das NumPy-Format unterstützen kann, ist es etwas einfacher als jetzt, die CPU (Python + NumPy) mit dem FPGA-Beschleuniger zu verbinden.

Recommended Posts

Gerätetreiber (NumPy-kompatibel) für Programme und Hardware, die unter Linux im Benutzerbereich ausgeführt werden, um Speicher gemeinsam zu nutzen
Gerätetreiber für Programme und Hardware, die unter Linux im Benutzerbereich ausgeführt werden, um Speicher freizugeben (V4L2_MEMORY_USERPTR Edition)
So führen Sie Python im virtuellen Raum aus (für MacOS)
Führen Sie den Lima-Treiber unter Debian GNU / Linux für Ultra96 / Ultra96-V2 aus
So installieren Sie OpenCV in Cloud9 und führen es in Python aus
Gerätetreiber zum "Cache-fähigen" Zugriff auf FPGA-Speicher von Linux