[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.
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.
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.
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
>>>
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