从SYSFS接口(HWMON)读取传感器数据有时会导致封锁调用(功能的执行时间比预期的更长)
我有一台运行Linux(BusyBox)的手臂机。我需要经常读取此文件中的数据/sys/class/class/hwmon/hwmon0/device/in7_input
,其中包含电压。它位于/sys/class/class/hwmon/
目录下的虚拟文件系统sysfs
中。
该文件包含看起来像这样的数据(SSHED到设备)。
root:~# cat /sys/class/hwmon/hwmon0/device/in7_input
10345
root:~# cat /sys/class/hwmon/hwmon0/device/in7_input
10250
通常,从该文件中读取数据的数据大约为1 ms
,但有时需要大约1秒
。不幸的是,对我来说,我无法在板凳上复制此问题,因为它在现场不太频繁。
我已经检查了CPU利用率,并且在此问题发生时通常小于60%
。我不确定为什么偶尔从该文件中读取会导致似乎是一个阻止调用,从而导致该功能的执行时间更长。
我不确定我是否正在处理虚拟文件系统上发生的更大问题sysfs
,或者我在readwoltage()
中是否有代码。非阻止。
这是我必须调整的代码的片段,
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
uint64_t GetClockCount(void);
float calculateLoopTime(uint32_t tUsec1, uint32_t tUsec2);
void readVoltage()
{
static const char VoltageFile[] = "/sys/class/hwmon/hwmon0/device/in7_input";
static int VoltageFD = -1;
if (-1 == VoltageFD)
{
VoltageFD = open(VoltageFile, O_RDONLY | O_NONBLOCK);
}
if (-1 == VoltageFD)
{
std::cout << "couldn't open FD for " << VoltageFile << std::endl;
}
else
{
static const size_t bufSize = 15;
char buffer[bufSize];
fd_set input;
FD_ZERO(&input);
FD_SET(VoltageFD, &input);
struct timeval to;
to.tv_sec = 0;
to.tv_usec = 0;
int n = 0;
n = select(VoltageFD + 1, &input, NULL, NULL, &to);
if (n > 0)
{
ssize_t bytes_read = pread(VoltageFD, buffer, bufSize, 0);
if (bytes_read > 0)
{
float voltage = (atof(buffer) / 1000.0f);
std::cout << "voltage= " << voltage << std::endl;
}
}
}
}
int main()
{
uint32_t start_time = GetClockCount();
readVoltage();
uint32_t end_time = GetClockCount();
float time_diff = calculateLoopTime(start_time, end_time);
std::cout << "function took " << time_diff << " ms to execute" << std::endl;
return 0;
}
uint64_t GetClockCount(void)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now))
return 0;
return static_cast<uint64_t>(now.tv_sec) * 1000000 + now.tv_nsec / 1000;
}
float calculateLoopTime(uint32_t tUsec1, uint32_t tUsec2)
{
float time_diff = 0;
if (tUsec1 != tUsec2)
{
uint32_t time_diff_temp = 0;
if (tUsec2 > tUsec1)
{
time_diff_temp = (tUsec2 - tUsec1);
}
// Scale from microseconds to milliseconds
time_diff = static_cast<float>(time_diff_temp) / 1000;
}
return time_diff;
}
您可以在此处运行代码,但是显然您不会得到电压,因为此文件/sys/class/class/class/hwmon/hwmon/hwmon0/device/in7_input
该在线IDE上不存在。
I have an ARM machine that runs Linux (BusyBox). I need to frequently read the data in this file /sys/class/hwmon/hwmon0/device/in7_input
which contains voltage. It's located in the virtual file system sysfs
under the /sys/class/hwmon/
directory.
The file contains data that looks like this (SSHed to the device).
root:~# cat /sys/class/hwmon/hwmon0/device/in7_input
10345
root:~# cat /sys/class/hwmon/hwmon0/device/in7_input
10250
Usually reading the data from that file takes about 1 ms
but there are occasions where it takes about 1 sec
. Unfortunately for me, I'm not able to replicate this issue on my bench since it doesn't happen very frequently on the field.
I have checked the CPU utilization and it's usually less than 60%
when this issue occurs. I'm not sure why occasionally reading from that file results in what appears to be a blocking call that results in a longer execution time for the function.
I'm not sure if I'm dealing with a bigger problem that's occurring on the virtual file system sysfs
or if the code I have in readVoltage()
isn't completely non-blocking.
Here is a snippet of that code that I had to tweak
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
uint64_t GetClockCount(void);
float calculateLoopTime(uint32_t tUsec1, uint32_t tUsec2);
void readVoltage()
{
static const char VoltageFile[] = "/sys/class/hwmon/hwmon0/device/in7_input";
static int VoltageFD = -1;
if (-1 == VoltageFD)
{
VoltageFD = open(VoltageFile, O_RDONLY | O_NONBLOCK);
}
if (-1 == VoltageFD)
{
std::cout << "couldn't open FD for " << VoltageFile << std::endl;
}
else
{
static const size_t bufSize = 15;
char buffer[bufSize];
fd_set input;
FD_ZERO(&input);
FD_SET(VoltageFD, &input);
struct timeval to;
to.tv_sec = 0;
to.tv_usec = 0;
int n = 0;
n = select(VoltageFD + 1, &input, NULL, NULL, &to);
if (n > 0)
{
ssize_t bytes_read = pread(VoltageFD, buffer, bufSize, 0);
if (bytes_read > 0)
{
float voltage = (atof(buffer) / 1000.0f);
std::cout << "voltage= " << voltage << std::endl;
}
}
}
}
int main()
{
uint32_t start_time = GetClockCount();
readVoltage();
uint32_t end_time = GetClockCount();
float time_diff = calculateLoopTime(start_time, end_time);
std::cout << "function took " << time_diff << " ms to execute" << std::endl;
return 0;
}
uint64_t GetClockCount(void)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now))
return 0;
return static_cast<uint64_t>(now.tv_sec) * 1000000 + now.tv_nsec / 1000;
}
float calculateLoopTime(uint32_t tUsec1, uint32_t tUsec2)
{
float time_diff = 0;
if (tUsec1 != tUsec2)
{
uint32_t time_diff_temp = 0;
if (tUsec2 > tUsec1)
{
time_diff_temp = (tUsec2 - tUsec1);
}
// Scale from microseconds to milliseconds
time_diff = static_cast<float>(time_diff_temp) / 1000;
}
return time_diff;
}
You can run the code here but obviously you won't get the the voltage since this file /sys/class/hwmon/hwmon0/device/in7_input
doesn't exist on that online IDE.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在
readwoltage()
中编写的代码是非障碍物。您可以使用以下事实,非块描述符上的read()
将返回e_again/e_wouldblock errno如果读取会阻塞,因此使用select> select()
删除行,并设置FD_SET (少代码)。您无法确定
getClockCount()
调用之间发生了什么。如果您的系统正在负载(就像您所说的60%一样),则可以做其他事情。硬件线程也可以执行其他操作,即使它没有100%的时间不做,它可以在切换回SYSFS阅读代码时引入一些抖动。为了更准确,尝试仅测量
pread()
调用时间,因此仍然有可能运行其他过程的代码,尤其是在谈论负载下的系统时。您也可以尝试使用
perf
检查程序中的情况。 look 在这里要查看perf可以显示运行程序期间发生多少个上下文切换。尝试通过使用以下方式测量呼叫普通的sysfs读取:
所有结果都应表明系统要做的其他事情和
pread()
呼叫不会在两次检查时不会阻止自身 - 一旦使用了非块在检查select()
返回准备就绪描述符时,标志和次要。The code you wrote in the
readVoltage()
is non-blocking. You can use the fact, thatread()
on non-blocking descriptor would return E_AGAIN / E_WOULDBLOCK errno if reading would block and therefore remove lines withselect()
and setting FD_SET (less code).You can't be sure what is happening between
GetClockCount()
calls. If your system is under load (like you say less 60%) it can be doing something else. Hardware thread can be doing some other operation even if it's not doing it 100% time it can introduce some jitter when switching back to your sysfs reading code.To be more accurate try to measure only
pread()
invocation time but therefore still be possibility for running some other process' code, especially when talking about system under load.You can also try to use
perf
to check out what's going on in your program. Look here to check out that perf can show how many context-switches occured during running your program.Try to also measure calling plain sysfs reading by using:
All the results should show that something other is done by the system and
pread()
call is not blocking itself as it's double checked - once using non-blocking flag and secondary when checking ifselect()
returned ready descriptor.