IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Intel 计划在Linux kernel中引入 User Interrupts,效率是eventfd的10倍 -> 正文阅读

[系统运维]Intel 计划在Linux kernel中引入 User Interrupts,效率是eventfd的10倍

未来Eventfd的替代品 User Interrupts

????????近期,在Linux kernel邮件列表中看到了Intel计划在最新的硬件中支持 User Interrupts功能,并在linux kernel社区中征求意见。邮件中给出了测试的性能数据,如下图:

IPI : inter-processor interrupt (邮件中将User task间的中断称为 User IPI)

进程间通信类型相对时间(已归一到 User IPI)
User IPI1.0
Signal14.8
Eventfd9.7
Pipe16.3
Domain17.3

详细介绍什么是 User Interrupts

????????用户中断(Uintr)是一种硬件技术,可以将中断直接传递到用户空间。

????????今天,几乎所有跨越特权界限的交流都是通过内核。 这些包括信号、管道、远程过程调用和基于硬件中断的通知。 User Interrupts提供了一个基础,通过避免通过内核的转换来实现常见的操作,以获得更高的效率(低延迟和低CPU利用率)

????????在User Interrupts硬件体系结构中,接收者总是被期望用户空间任务( user space task)。 但是,一个User Interrupt 可以由另一个用户空间任务、内核或外部源(如设备)发送


底层是如何工作的?

????????User Interrupts是一种中断传递机制。中断首先被发送到某个内存位置,然后再被发送到具体的接收者(要求接收者的CPL=3)。

内核管理相关的数据结构

  • UPID : User Posted Interrupt Descriptor — 保持接收者的中断向量信息和通知状态(如正在进行的通知、被抑制通知);

  • UITT : User Interrupt Target Table — 存储UPID指针 和 用于发送端中断路由的向量信息 ;

每个任务的中断状态通过 MSRs 记录,并且在上下文切换期间由内核恢复。

User IPI

senduipi - 根据UITT 索引发送一个 user IPI 到目标task

当 User IPI 发送者执行’senduipi '时,硬件根据UITT和index确定中断发送目标,并将中断向量(63-0)推送到接收者的UPID中。

如果接收端正在运行(CPL=3),发送端cpu将发送一个物理IPI到接收机的cpu。 在接收端,此IPI被检测为用户中断。 调用接收者的用户中断处理程序,并将中断向量(63-0)压栈。


应用接口

????????User Interrupts (Uintr)是一个可选择的特性(不像信号)。希望使用Uintr的应用程序需要使用与Uintr相关的系统调用来向内核注册自己。Uintr接收器总是一个用户空间任务。一个Uintr sender可以是另一个用户空间任务,内核或设备。

  • 一个接收器可以注册/注销一个中断处理程序使用Uintr接收器相关的系统调用:
    • uintr_register_handler(handler, flags)
    • uintr_unregister_handler(flags)
  • 系统调用还允许接收者注册一个vector 并创建一个用户中断文件描述符 — uintr_fd:
    • uintr_fd = uintr_create_fd(vector, flags)

当eventfd或signal 用于频繁的用户空间事件通知时,Uintr是有用的。uintr_fd的语义有点类似于eventfd()或pipe的写端。

  • 任何发送方都可以使用 uintr_fd 向接收方传递事件(例如,中断)。发送方可以使用uintr_fd 管理与接收者之间的连接:
    • uipi_index = uintr_register_sender(uintr_fd, flags)
  • 在初始设置之后,发送端可以使用 SENDUIPI 指令以及uipi_index 参数来生成 User IPI,而不需要任何内核干预:
    • SENDUIPI <uipi_index>

如果接收端正在运行(CPL=3),则直接交付用户中断,而不需要内核转换。如果接收端没有运行,那么当接收端获得上下文切换回时,中断就会被交付。如果接收者在内核中被阻塞,用户中断被传递到内核,内核然后解除阻塞,向接收者传递中断。

  • 如果发送方是内核或设备,则可以将 uintr_fd 传递给相关的内核实体,以允许它们设置连接,然后生成用于事件传递的 user interrupt。

具体的例子

#define _GNU_SOURCE
#include <syscall.h>
#include <stdio.h>
#include <unistd.h>
#include <x86gprintrin.h>
#include <pthread.h>
#include <stdlib.h>

unsigned long uintr_received;
unsigned int uintr_fd;

void __attribute__((interrupt))__attribute__((target("general-regs-only", "inline-all-stringops")))
uintr_handler(struct __uintr_frame *ui_frame,
	      unsigned long long vector)
{
	uintr_received = 1;
}

void receiver_setup_interrupt(void)
{
	int vector = 0;
	int ret;

	/* Register interrupt handler */
	if (uintr_register_handler(uintr_handler, 0)) {
		printf("[FAIL]\tInterrupt handler register error\n");
		exit(EXIT_FAILURE);
	}

	/* Create uintr_fd */
	ret = uintr_create_fd(vector, 0);
	if (ret < 0) {
		printf("[FAIL]\tInterrupt vector registration error\n");
		exit(EXIT_FAILURE);
	}

	uintr_fd = ret;
}

void *sender_thread(void *arg)
{
	long sleep_usec = (long)arg;
	int uipi_index;

	uipi_index = uintr_register_sender(uintr_fd, 0);
	if (uipi_index < 0) {
		printf("[FAIL]\tSender register error\n");
		return NULL;
	}

	/* Sleep before sending IPI to allow the receiver to block in the kernel */
	if (sleep_usec)
		usleep(sleep_usec);

	printf("\tother thread: sending IPI\n");
	_senduipi(uipi_index);

	uintr_unregister_sender(uintr_fd, 0);

	return NULL;
}

static inline void cpu_relax(void)
{
	asm volatile("rep; nop" ::: "memory");
}

void test_base_ipi(void)
{
	pthread_t pt;

	uintr_received = 0;
	if (pthread_create(&pt, NULL, &sender_thread, NULL)) {
		printf("[FAIL]\tError creating sender thread\n");
		return;
	}

	printf("[RUN]\tSpin in userspace (waiting for interrupts)\n");
	// Keep spinning until interrupt received
	while (!uintr_received)
		cpu_relax();

	printf("[OK]\tUser interrupt received\n");
}

void test_blocking_ipi(void)
{
	pthread_t pt;
	long sleep_usec;

	uintr_received = 0;
	sleep_usec = 1000;
	if (pthread_create(&pt, NULL, &sender_thread, (void *)sleep_usec)) {
		printf("[FAIL]\tError creating sender thread\n");
		return;
	}

	printf("[RUN]\tBlock in the kernel (waiting for interrupts)\n");
	uintr_wait(0);
	if (uintr_received)
		printf("[OK]\tUser interrupt received\n");
	else
		printf("[FAIL]\tUser interrupt not received\n");
}

int main(int argc, char *argv[])
{
	receiver_setup_interrupt();

	/* Enable interrupts */
	_stui();

	test_base_ipi();

	test_blocking_ipi();

	close(uintr_fd);
	uintr_unregister_handler(0);

	exit(EXIT_SUCCESS);
}

在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-09-18 10:39:18  更:2021-09-18 10:41:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:46:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码