- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我想计算(或多或少)一段代码的确切指令数量。此外,我希望在通过特定数量的指令后收到信号。
为此,我使用了由 perf_event_open .
我正在使用联机帮助页建议的第二种方式来实现溢出信号:
Signal overflow
Events can be set to deliver a signal when a threshold is crossed. The signal handler is set up using the poll(2), select(2), epoll(2) and fcntl(2), system calls.
[...]
The other way is by use of the PERF_EVENT_IOC_REFRESH ioctl. This ioctl adds to a counter that decrements each time the event overflows. When nonzero, a POLL_IN signal is sent on overflow, but once the value reaches 0, a signal is sent of type POLL_HUP and the underlying event is disabled.
PERF_EVENT_IOC_REFRESH ioctl的进一步解释:
PERF_EVENT_IOC_REFRESH
Non-inherited overflow counters can use this to enable a counter for a number of overflows specified by the argument, after which it is disabled. Subsequent calls of this ioctl add the argument value to the current count. A signal with POLL_IN set will happen on each overflow until the count reaches 0; when that happens a signal with POLL_HUP set is sent and the event is disabled. Using an argument of 0 is considered undefined behavior.
一个非常简单的示例如下所示:
#define _GNU_SOURCE 1
#include <asm/unistd.h>
#include <fcntl.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long perf_event_open(struct perf_event_attr* event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags);
}
static void perf_event_handler(int signum, siginfo_t* info, void* ucontext) {
if(info->si_code != POLL_HUP) {
// Only POLL_HUP should happen.
exit(EXIT_FAILURE);
}
ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1);
}
int main(int argc, char** argv)
{
// Configure signal handler
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = perf_event_handler;
sa.sa_flags = SA_SIGINFO;
// Setup signal handler
if (sigaction(SIGIO, &sa, NULL) < 0) {
fprintf(stderr,"Error setting up signal handler\n");
perror("sigaction");
exit(EXIT_FAILURE);
}
// Configure perf_event_attr struct
struct perf_event_attr pe;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS; // Count retired hardware instructions
pe.disabled = 1; // Event is initially disabled
pe.sample_type = PERF_SAMPLE_IP;
pe.sample_period = 1000;
pe.exclude_kernel = 1; // excluding events that happen in the kernel-space
pe.exclude_hv = 1; // excluding events that happen in the hypervisor
pid_t pid = 0; // measure the current process/thread
int cpu = -1; // measure on any cpu
int group_fd = -1;
unsigned long flags = 0;
int fd = perf_event_open(&pe, pid, cpu, group_fd, flags);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
perror("perf_event_open");
exit(EXIT_FAILURE);
}
// Setup event handler for overflow signals
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
fcntl(fd, F_SETSIG, SIGIO);
fcntl(fd, F_SETOWN, getpid());
ioctl(fd, PERF_EVENT_IOC_RESET, 0); // Reset event counter to 0
ioctl(fd, PERF_EVENT_IOC_REFRESH, 1); //
// Start monitoring
long loopCount = 1000000;
long c = 0;
long i = 0;
// Some sample payload.
for(i = 0; i < loopCount; i++) {
c += 1;
}
// End monitoring
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); // Disable event
long long counter;
read(fd, &counter, sizeof(long long)); // Read event counter value
printf("Used %lld instructions\n", counter);
close(fd);
}
所以基本上我在做以下事情:
perf_event_open
创建一个新的性能计数器(返回一个文件描述符)fcntl
向文件描述符添加信号发送行为。当执行有效负载循环时,在某个时刻将执行 1000 条指令(sample_interval
)。根据perf_event_open manpage这会触发溢出,然后递减内部计数器。一旦该计数器达到零,“将发送一个 POLL_HUP 类型的信号,并禁用底层事件。”
当发送信号时,停止当前进程/线程的控制流,并执行信号处理程序。场景:
这种情况意味着两件事:
ucontext
访问)将直接指向导致溢出的指令。 基本上你可以说,信号行为可以被视为同步。
这是我想要实现的完美语义。
但是,就我而言,我配置的信号通常是相当异步的,并且可能需要一些时间才能最终交付并执行信号处理程序。这对我来说可能是个问题。
例如,考虑以下场景:
这种情况意味着两件事:
到目前为止,我已经对上面的示例进行了大量测试,没有遇到支持第一种情况的遗漏指令。
但是,我真的很想知道我是否可以依赖这个假设。内核中发生了什么?
最佳答案
I want to count the (more or less) exact amount of instructions for some piece of code. Additionally, I want to receive a Signal after a specific amount of instructions passed.
您有两个可能相互冲突的任务。当你想要计数(一些硬件事件的精确数量)时,只需在计数模式下使用你的 CPU 的性能监控单元(不要设置 sample_period
/sample_freq
of perf_event_attr
使用的结构)并将测量代码放在目标程序中(就像在您的示例中所做的那样)。在这种模式下根据man page of perf_event_open
不会产生溢出(CPU的PMU通常是64位宽,使用采样模式时不设置小负值也不会溢出):
Overflows are generated only by sampling events (sample_period must a nonzero value).
要对部分程序进行计数,请使用 perf_event_open 的 ioctl
返回 fd,如 man page 中所述
perf_event ioctl calls - Various ioctls act on perf_event_open() file descriptors: PERF_EVENT_IOC_ENABLE ... PERF_EVENT_IOC_DISABLE ... PERF_EVENT_IOC_RESET
您可以使用 rdpmc
(在 x86 上)或通过 fd 上的 read
系统调用读取当前值,就像来自 the man page 的简短示例一样:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
int
main(int argc, char **argv)
{
struct perf_event_attr pe;
long long count;
int fd;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
printf("Measuring instruction count for this printf\n");
/* Place target code here instead of printf */
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long));
printf("Used %lld instructions\n", count);
close(fd);
}
Additionally, I want to receive a Signal after a specific amount of instructions passed.
您真的想要获得信号,还是只需要每执行 1000 条指令就需要指令指针?如果您想收集指针,请使用带采样模式的perf_even_open
,但从其他程序执行以禁用事件收集代码的测量。此外,如果您不对每次溢出使用信号(大量的内核跟踪器交互以及从/切换到内核),而是使用 perf_events 的功能来收集多个溢出事件,那么它对您的目标程序的负面影响也会更小进入单个 mmap 缓冲区并轮询此缓冲区。在 PMU perf 中断处理程序的溢出中断将被调用以将指令指针保存到缓冲区中,然后计数将被重置并且程序将返回执行。在您的示例中,perf 中断处理程序将唤醒您的程序,它将执行多个系统调用,返回内核,然后内核将重新启动目标代码(因此每个样本的开销大于使用 mmap 和解析它)。使用 precise_ip
标志,您可以激活 PMU 的高级采样(如果它有这样的模式,如 PEBS 和 PREC_DIST in intel x86/em64t for some counters like INST_RETIRED, UOPS_RETIRED, BR_INST_RETIRED, BR_MISP_RETIRED, MEM_UOPS_RETIRED, MEM_LOAD_UOPS_RETIRED , MEM_LOAD_UOPS_LLC_HIT_RETIRED 和 simple hack 到 cycles
;或像 AMD x86/amd64 的 IBS;关于 PEBS and IBS 的论文),当指令地址直接由硬件保存时,具有低滑动。一些非常先进的 PMU 能够在硬件中进行采样,将多个事件的溢出信息连续存储,并自动重置计数器而无需软件中断(precise_ip
上的一些描述是 in the same paper )。
我不知道在 perf_events 子系统和您的 CPU 中是否有可能同时激活两个 perf_event 任务:既计算目标进程中的事件,又同时从其他进程采样。使用高级 PMU,这在硬件中是可能的,现代内核中的 perf_events 可能允许它。但是您没有提供有关您的内核版本以及您的 CPU 供应商和系列的详细信息,因此我们无法回答这部分。
您也可以尝试其他 API 来访问 PMU,例如 PAPI 或 likwid (https://github.com/RRZE-HPC/likwid)。其中一些可能会直接读取 PMU 寄存器(有时是 MSR),并且可能允许在启用计数时同时进行采样。
关于linux - perf_event_open 溢出信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24474397/
我有一个 div(蓝色框),它在父元素(红色框)内的页面上绝对定位,我需要将 overflow-y 设置为隐藏,以便它强制 Y 轴上的溢出内容切掉了,但我希望任何溢出-x 的内容都可见。 HTML:
请参阅以下帖子以获取突出显示我的问题和可能的解决方案的图片: CSS overflow-y:visible, overflow-x:scroll 但是,当您实际移动滚动条时,此策略会中断。在建议的实现
我在搜索中看到过几个类似的问题,但要么没有正确回答问题,要么没有给出答案。所以,我再问一次。 .parent { overflow-y:scroll; overflow-x:visible; wid
我读过这个CSS overflow-x hidden and overflow-y visible (以及很多其他帖子)但我无法在我的具体情况下使用它。 我正在使用 slick-slider并想添加下
我有以下 Spark 作业,试图将所有内容保留在内存中: val myOutRDD = myInRDD.flatMap { fp => val tuple2List: ListBuffer[(St
我有疑问 两个16位的值加上最大值,16位机会不会溢出? 我会详细说明 unsigned short a; unsigned short b; unsigned long c; c=(unsigne
我有这个 HTML 和 CSS,但“溢出:隐藏”标签在 Firefox 中不起作用。这让我感到难过...有人知道为什么它不起作用吗?是因为A标签不支持overflow标签吗? #page_sideba
我正在开发一个程序,用于在 C++ 中分解非常大的数字(20 位或更多),并且正在使用 GMP 来处理溢出问题。我的程序对于大约 10 位或更少的数字运行良好,但是当我向它抛出一个 15 位数字时,它
我创建了一个 Canvas ,并在其中放置了一个StackPanel。 StackPanel是水平的,它接受缩略图图像的列表。 Canvas 具有固定的大小。当我放置的缩略图多于Canvas宽度不能容
当 g_array_append_val() 时会发生什么或 GLib 中的其他附加/前置函数之一,使 GArray 的长度大于 guint (unsigned int) 所能容纳的长度? 文档对此没
overflow-x:hidden 和 overflow:hidden; 有什么区别? 我所知道的是overflow-x:hidden;禁用水平滚动,但当我使用它时,它不仅仅适用于 Firefox,所
我们正在运行 Solr 来索引大量数据,但遇到了一个非常有趣的问题,我无法在任何地方找到任何帮助。 似乎 Solr 使用带符号的 32 位整数来计算索引中当前的文档数。我们刚刚达到了这个数字,我们的
这是我的查询: 从相似性中选择 COUNT(*),其中 T1Similarity = 0 或 T2Similarity = 0 结果如下: Msg 8115, Level 16, State 2, L
int main(void) { char x1 = 0x81; char x2 = 0x1; int a, b; a = x1
我有一个 div,其中的内容通过查询的 append() 定期附加到它。随着内容越来越长,最终会溢出div。我不希望在溢出时出现滚动条,但仍然让内容向上滚动以显示下面的新内容。 这可能吗?当我使用 o
我为 UITextField 创建了一个简单的子类,它按预期工作。我遇到的唯一问题是当文本值变得太大时,它会溢出到清除按钮中。 我似乎无法找到如何仅更改文本的右侧以具有一些填充而不与清除按钮相交的方法
我想要一个包括下拉菜单的粘性导航栏。但是,当我将鼠标悬停在它上面时,下拉菜单没有显示。 如果我删除 overflow: hidden;在无序列表中,当我向下滚动时,导航栏设法保持在顶部,但是导航栏是不
我正在研究一些按钮。我想要一个翻转状态,我在一个 div 的图像中有这个,溢出:隐藏以隐藏不活动的状态。它有时有效,但有时看起来像这样: 最奇怪的是,当我尝试使用 Chrome Web Inspect
基本上,我正在尝试创建一个六边形形状,它内部有一个圆圈,圆圈的多余部分应该被隐藏。演示:https://codepen.io/AskSaikatSinha/pen/jwXNPJ?editors=110
这似乎是一个相当常见且不那么奇特的用例,但我以前没有遇到过。我设置了一支笔,但无法在那里复制它,我正在努力找出原因。 Demo Pen 左侧边栏有一个用于元素列表的自定义滚动窗口,但是虽然设置 ove
我是一名优秀的程序员,十分优秀!