- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要为带有 SRAM 的 PCIe 设备编写一个 linux 内核驱动程序。
对于第一次尝试,我编写了一个驱动程序来使用字符设备从 PCIe 访问 SRAM。
一切正常,但有一个问题。 SRAM 很慢 1MB 读/写大约需要 2 秒,这是硬件限制。读/写时 CPU 100% 忙。女巫是个问题。我不需要速度,读/写可以很慢,但为什么要占用这么多 CPU?
缓冲区用pci_iomap
初始化:
g_mmio_buffer[0] = pci_iomap(pdev, SRAM_BAR_H, g_mmio_length);
读/写函数如下所示:
static ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *off) {
unsigned long rval;
size_t copied;
rval = copy_to_user(buf, g_mmio_buffer[SRAM_BAR] + *off, len);
if (rval < 0) return -EFAULT;
copied = len - rval;
*off += copied;
return copied;
}
static ssize_t dev_write(struct file *fp, const char *buf, size_t len, loff_t *off) {
unsigned long rval;
size_t copied;
rval = copy_from_user(g_mmio_buffer[SRAM_BAR] + *off, buf, len);
if (rval < 0) return -EFAULT;
copied = len - rval;
*off += copied;
return copied;
}
问题是 CPU 使用率高我该怎么办?
我应该重写驱动程序以使用 block 设备而不是字符吗?
允许 CPU 在读取/保存数据时处理另一个进程?
最佳答案
正如@0andriy 所指出的,您不应该直接访问 iomem。有memcpy_toio()
等函数和 memcpy_fromio()
可以在 iomem 和普通内存之间复制,但它们只适用于内核虚拟地址。
NOTE: The use of
get_user_pages_fast()
,set_page_dirty_lock()
andput_page()
described below should be changed for Linux kernel version 5.6 onwards. The required changes are described later.
为了在不使用中间数据缓冲区的情况下从用户空间地址复制到 iomem,需要将用户空间内存页“固定”到物理内存中。这可以使用 get_user_pages_fast()
来完成.但是,固定页面可能位于内核永久映射内存之外的“高端内存”(highmem) 中。这些页面需要使用 kmap_atomic()
在短时间内临时映射到内核虚拟地址空间。 . (有管理 kmap_atomic()
的使用的规则,还有用于长期映射 highmem 的其他函数。查看 highmem 文档以获取详细信息。)
一旦用户空间页面被映射到内核虚拟地址空间,memcpy_toio()
和 memcpy_fromio()
可用于在该页面和 iomem 之间进行复制。
由 kmap_atomic()
临时映射的页面需要通过 kunmap_atomic()
取消映射.
get_user_pages_fast()
固定的用户内存页面需要通过调用 put_page()
单独取消固定, 但如果页面内存已被写入(例如 memcpy_fromio()
,它必须首先被 set_page_dirty_lock()
标记为“脏”,然后再调用 put_page()
。
Note: Change for kernel version 5.6 onwards.
- The call to
get_user_pages_fast()
should be changed topin_user_pages_fast()
.- Dirty pages pinned by
pin_user_pages_fast()
should be unpinned byunpin_user_pages_dirty_lock()
with the last argument set true.- Clean pages pinned by
pin_user_pages_fast()
should be unpinned byunpin_user_page()
,unpin_user_pages()
, orunpin_user_pages_dirty_lock()
with the last argument set false.put_page()
must not be used to unpin pages pinned bypin_user_pages_fast()
.- For code to be compatible with earlier kernel versions, the availability of
pin_user_pages_fast()
,unpin_user_page()
, etc. can be determined by whether theFOLL_PIN
macro has been defined by#include <linux/mm.h>
.
将所有这些放在一起,可以使用以下函数在用户内存和 iomem 之间进行复制:
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/io.h>
/**
* my_copy_to_user_from_iomem - copy to user memory from MMIO
* @to: destination in user memory
* @from: source in remapped MMIO
* @n: number of bytes to copy
* Context: process
*
* Returns number of uncopied bytes.
*/
long my_copy_to_user_from_iomem(void __user *to, const void __iomem *from,
unsigned long n)
{
might_fault();
if (!access_ok(to, n))
return n;
while (n) {
enum { PAGE_LIST_LEN = 32 };
struct page *page_list[PAGE_LIST_LEN];
unsigned long start;
unsigned int p_off;
unsigned int part_len;
int nr_pages;
int i;
/* Determine pages to do this iteration. */
p_off = offset_in_page(to);
start = (unsigned long)to - p_off;
nr_pages = min_t(int, PAGE_ALIGN(p_off + n) >> PAGE_SHIFT,
PAGE_LIST_LEN);
/* Lock down (for write) user pages. */
#ifdef FOLL_PIN
nr_pages = pin_user_pages_fast(start, nr_pages, FOLL_WRITE, page_list);
#else
nr_pages = get_user_pages_fast(start, nr_pages, FOLL_WRITE, page_list);
#endif
if (nr_pages <= 0)
break;
/* Limit number of bytes to end of locked-down pages. */
part_len =
min(n, ((unsigned long)nr_pages << PAGE_SHIFT) - p_off);
/* Copy from iomem to locked-down user memory pages. */
for (i = 0; i < nr_pages; i++) {
struct page *page = page_list[i];
unsigned char *p_va;
unsigned int plen;
plen = min((unsigned int)PAGE_SIZE - p_off, part_len);
p_va = kmap_atomic(page);
memcpy_fromio(p_va + p_off, from, plen);
kunmap_atomic(p_va);
#ifndef FOLL_PIN
set_page_dirty_lock(page);
put_page(page);
#endif
to = (char __user *)to + plen;
from = (const char __iomem *)from + plen;
n -= plen;
part_len -= plen;
p_off = 0;
}
#ifdef FOLL_PIN
unpin_user_pages_dirty_lock(page_list, nr_pages, true);
#endif
}
return n;
}
/**
* my_copy_from_user_to_iomem - copy from user memory to MMIO
* @to: destination in remapped MMIO
* @from: source in user memory
* @n: number of bytes to copy
* Context: process
*
* Returns number of uncopied bytes.
*/
long my_copy_from_user_to_iomem(void __iomem *to, const void __user *from,
unsigned long n)
{
might_fault();
if (!access_ok(from, n))
return n;
while (n) {
enum { PAGE_LIST_LEN = 32 };
struct page *page_list[PAGE_LIST_LEN];
unsigned long start;
unsigned int p_off;
unsigned int part_len;
int nr_pages;
int i;
/* Determine pages to do this iteration. */
p_off = offset_in_page(from);
start = (unsigned long)from - p_off;
nr_pages = min_t(int, PAGE_ALIGN(p_off + n) >> PAGE_SHIFT,
PAGE_LIST_LEN);
/* Lock down (for read) user pages. */
#ifdef FOLL_PIN
nr_pages = pin_user_pages_fast(start, nr_pages, 0, page_list);
#else
nr_pages = get_user_pages_fast(start, nr_pages, 0, page_list);
#endif
if (nr_pages <= 0)
break;
/* Limit number of bytes to end of locked-down pages. */
part_len =
min(n, ((unsigned long)nr_pages << PAGE_SHIFT) - p_off);
/* Copy from locked-down user memory pages to iomem. */
for (i = 0; i < nr_pages; i++) {
struct page *page = page_list[i];
unsigned char *p_va;
unsigned int plen;
plen = min((unsigned int)PAGE_SIZE - p_off, part_len);
p_va = kmap_atomic(page);
memcpy_toio(to, p_va + p_off, plen);
kunmap_atomic(p_va);
#ifndef FOLL_PIN
put_page(page);
#endif
to = (char __iomem *)to + plen;
from = (const char __user *)from + plen;
n -= plen;
part_len -= plen;
p_off = 0;
}
#ifdef FOLL_PIN
unpin_user_pages(page_list, nr_pages);
#endif
}
return n;
}
其次,您可能可以通过替换 pci_iomap()
将 iomem 映射为“写入组合”来加速内存访问。与 pci_iomap_wc()
.
第三,在访问慢速内存时避免等待 CPU 的唯一真正方法是不使用 CPU,而是使用 DMA 传输。其细节在很大程度上取决于您的 PCIe 设备的总线主控 DMA 功能(如果有的话)。用户内存页面在 DMA 传输期间仍需要固定(例如,通过 get_user_pages_fast()
或 pin_user_pages_fast()
,视情况而定),但不需要通过 kmap_atomic()
临时映射.
关于linux - 读/写字符设备时如何避免高CPU使用率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58413297/
我正在寻找一种方法来创建根据价格选择我的产品的过滤器(选择下拉菜单)。 我知道这样的查询是完全可能的: SELECT * FROM products ORDER BY price ASC SELECT
函数参数中或显示尺寸时(高度,宽度)的顺序是否有约定? 最佳答案 我不知道大量的语言,但我使用过的语言(宽度,高度)。它更适合沿着 (x, y) 坐标线。 关于language-agnostic -
在我的表单中,我让用户输入房间的长度高度和宽度以获得 m2、m3 和瓦特的计算值。但是用户也应该能够直接输入 height 和 m2 来获取值。我尝试了很多语法,但 if else 不能正常工作。我知
我在 Elasticsearch 中创建了一个索引,看起来像 {"amazingdocs":{"aliases":{},"mappings":{"properties":{"Adj Close":{"
我有以下功能,我需要清除数据库中的所有图片列并移动到文件系统。当我一次性完成这一切时,内存太多并且会崩溃。我切换到递归函数并执行 20 次写入和批量操作。 我需要为大约 6 个表执行此操作。我的 Re
我正在编写一个函数来计算 PI 的值,并将其作为 double 值返回。到目前为止,一切都很好。但是一旦函数到达小数点后14位,它就不能再保存了。我假设这是因为 double 有限。我应该怎么做才能继
2020年是中国CDN行业从98年诞生到今天快速发展的第二十四年,相关数据显示,全国感知网速持续上扬,达到了3.29兆/秒,标志着在宽带中国的政策指导下,中国的网速水平正在大步赶上世界发达国家的水平
在 aerospike 集合中,我们有四个 bin userId、adId、timestamp、eventype,主键是 userId:timestamp。在 userId 上创建二级索引以获取特定用
$('#container').highcharts('Map', { title : { text : 'Highmaps basic demo'
有没有办法显示自定义宽度/高度的YouTube视频? 最佳答案 在YouTube网站上的this link中: You can resize the player by editing the obj
我使用 Highcharts ,我想在 Highcharts 状态下悬停时制作动态不同的颜色。 正如你可以看到不同的颜色,这就是我做的 var usMapChart , data = [] ; va
在所有节点上运行 tpstats 后。我看到很多节点都有大量的 ALL TIME BLOCKED NTR。我们有一个 4 节点集群,NTR ALL TIME BLOCKED 的值为: 节点 1:239
我发现 APC 上存在大量碎片 (>80%),但实际上性能似乎相当不错。我有 read another post这建议在 wordpress/w3tc 中禁用对象缓存,但我想知道减少碎片是否比首先缓存
对于我的脚本类(class),我们必须制作更高/更低的游戏。到目前为止,这是我的代码: import random seedVal = int(input("What seed should be u
我发现 APC 上存在大量碎片 (>80%),但实际上性能似乎相当不错。我有 read another post这建议在 wordpress/w3tc 中禁用对象缓存,但我想知道减少碎片是否比首先缓存
对于我的脚本类(class),我们必须制作更高/更低的游戏。到目前为止,这是我的代码: import random seedVal = int(input("What seed should be u
我已经 seen >2 字节的 unicode 代码点,如 U+10000 可以成对编写,如 \uD800\uDC00。它们似乎以半字节 d 开头,但我只注意到了这一点。 这个 split Actio
有人可以帮我理解为什么我的饼图百分比计算不正确吗?看截图: 根据我的计算,如 RHS 上所示,支出百分比应为 24.73%。传递给 Highcharts 的值如下:- 花费:204827099.36-
我阅读了有关该问题的所有答案,但我还没有找到任何解决方案。 我有一个应用程序,由我的 api 服务器提供。 Wildfly 8.1 和 Mysql 5.6。当查看时间到来时(Wildfly 服务器连接
我正在用选定的项目创建圆形导航。当用户单击任何项目时,它将移动到定义的特定点。一切都很好,除了当你继续点击项目时,当动画表现不同并且项目在 360 度圆中移动并且它被重置直到你重复场景时,我希望它
我是一名优秀的程序员,十分优秀!