- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在实现一种算法 (SpookyHash),该算法通过将指针转换为 (ulong*)
来将任意数据视为 64 位整数。 (这是 SpookyHash 工作方式所固有的,不这样做的重写不是一个可行的解决方案)。
这意味着它最终可能会读取未在 8 字节边界上对齐的 64 位值。
在某些 CPU 上,这工作正常。在某些情况下,它会非常慢。在其他人身上,它会导致错误(异常或不正确的结果)。
因此,我有代码来检测未对齐的读取,并在必要时将数据 block 复制到 8 字节对齐的缓冲区,然后再处理它们。
但是,我自己的机器有一个 Intel x86-64。这足以容忍未对齐的读取,如果我忽略对齐问题,它会提供更快的性能,就像 x86 一样。它还允许使用类似于 memcpy
和 memzero
的方法来处理 64 字节 block 以实现另一个提升。这两项性能改进是相当可观的,足以使这种优化远非过早。
所以。我有一个非常值得在某些芯片上进行的优化(就此而言,可能是最有可能在其上运行此代码的两个芯片),但在其他芯片上可能是致命的或性能较差。显然,理想的做法是检测我正在处理的是哪种情况。
一些进一步的要求:
这旨在成为支持 .NET 或 Mono 的所有系统的跨平台库。因此,特定于给定操作系统的任何内容(例如 P/调用操作系统调用)都是不合适的,除非它可以在调用不可用时安全地降级。
假阴性(将实际上安全的芯片识别为对优化不安全)是可以容忍的,而假阳性则不是。
昂贵的操作可以,只要能做一次,然后把结果缓存起来。
该库已经使用了不安全的代码,因此没有必要避免这种情况。
到目前为止,我有两种方法:
首先是初始化我的标志:
private static bool AttemptDetectAllowUnalignedRead()
{
switch(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"))
{
case "x86": case "AMD64": // Known to tolerate unaligned-reads well.
return true;
}
return false; // Not known to tolerate unaligned-reads well.
}
另一个是,由于避免未对齐读取所需的缓冲区复制是使用 stackalloc
创建的,并且由于在 x86(包括 32 位模式下的 AMD64)上,stackalloc
处理 64 位类型有时可能会返回一个 4 字节对齐但不是 8 字节对齐的指针,然后我可以在此时告诉您不需要对齐解决方法,并且再也不会尝试:
if(!AllowUnalignedRead && length != 0 && (((long)message) & 7) != 0) // Need to avoid unaligned reads.
{
ulong* buf = stackalloc ulong[2 * NumVars]; // buffer to copy into.
if((7 & (long)buf) != 0) // Not 8-byte aligned, so clearly this was unnecessary.
{
AllowUnalignedRead = true;
Thread.MemoryBarrier(); //volatile write
虽然后者仅适用于 32 位执行(即使允许未对齐的 64 位读取,stackalloc
的良好实现也不会强制它们在 64 位处理器上运行)。它还可能会给出误报,因为处理器可能会坚持 4 字节对齐,这会产生同样的问题。
是否有任何改进的想法,或者更好的是,一种不会像上述两种方法那样产生漏报的方法?
最佳答案
好吧,这是我自己的最终答案。当我在这里回答我自己的问题时,我对评论有很大的帮助。
Ben Voigt 和 J Trana 的评论让我意识到了一些事情。虽然我的具体问题是一个 bool 问题,但一般问题不是:
几乎所有现代处理器都会因未对齐读取而受到性能影响,只是其中一些影响非常小,与避免它的成本相比微不足道。
因此,“哪些处理器允许非对齐读取的成本足够低?”这个问题确实没有答案。而是,“对于我目前的情况,哪些处理器允许未对齐读取足够便宜。因此,任何完全一致和可靠的方法不仅是不可能的,而且作为与特定情况无关的问题,毫无意义。
因此,已知足以处理手头代码的白名单案例是唯一的出路。
虽然在 Windows 上使用 .NET 和 Mono 时我在 *nix 上使用 Mono 获得成功,但我应该归功于 Stu。上面评论中的讨论将我的思路引向了一种相对简单但相当有效的方法(如果 Stu 发布了一个答案“我认为你应该将你的方法建立在让特定于平台的代码安全运行的基础上”,我会接受它,因为这是他的一个建议的症结所在,也是我所做工作的关键)。
和之前一样,我首先尝试检查通常会在 Windows 中设置的环境变量,而不是在任何其他操作系统上设置。
如果失败,我会尝试运行 uname -p
并解析结果。这可能会因多种原因而失败(未在 *nix 上运行,没有足够的权限,在具有 uname
命令但没有 -p
标志的 *nix 形式之一上运行)。任何异常,我只是吃掉异常,然后尝试uname -m
,它的使用范围更广,但相同芯片的标签种类更多。
如果失败了,我就再次吃掉任何异常,并认为这是我的白名单没有得到满足的情况:我可以得到漏报,这意味着性能不佳,但不会导致错误的误报.如果我了解到给定的芯片系列与不尝试避免未对齐读取的代码分支同样更好,我也可以很容易地添加到白名单。
当前代码如下:
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "Many exceptions possible, all of them survivable.")]
[ExcludeFromCodeCoverage]
private static bool AttemptDetectAllowUnalignedRead()
{
switch(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"))
{
case "x86":
case "AMD64": // Known to tolerate unaligned-reads well.
return true;
}
// Analysis disable EmptyGeneralCatchClause
try
{
return FindAlignSafetyFromUname();
}
catch
{
return false;
}
}
[SecuritySafeCritical]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "Many exceptions possible, all of them survivable.")]
[ExcludeFromCodeCoverage]
private static bool FindAlignSafetyFromUname()
{
var startInfo = new ProcessStartInfo("uname", "-p");
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.LoadUserProfile = false;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
try
{
var proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
using(var output = proc.StandardOutput)
{
string line = output.ReadLine();
if(line != null)
{
string trimmed = line.Trim();
if(trimmed.Length != 0)
switch(trimmed)
{
case "amd64":
case "i386":
case "x86_64":
case "x64":
return true; // Known to tolerate unaligned-reads well.
}
}
}
}
catch
{
// We don't care why we failed, as there are many possible reasons, and they all amount
// to our not having an answer. Just eat the exception.
}
startInfo.Arguments = "-m";
try
{
var proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
using(var output = proc.StandardOutput)
{
string line = output.ReadLine();
if(line != null)
{
string trimmed = line.Trim();
if(trimmed.Length != 0)
switch(trimmed)
{
case "amd64":
case "i386":
case "i686":
case "i686-64":
case "i86pc":
case "x86_64":
case "x64":
return true; // Known to tolerate unaligned-reads well.
default:
if(trimmed.Contains("i686") || trimmed.Contains("i386"))
return true;
return false;
}
}
}
}
catch
{
// Again, just eat the exception.
}
// Analysis restore EmptyGeneralCatchClause
return false;
}
关于c# - 检测 CPU 对齐要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20951038/
我有一个类和构造函数,如下所示: def init(log, edge): if edge: return Helper(log, edge) return Booka
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 4年前关闭。 Improve this questi
有人知道在 mongo 上安装标准 ubuntu 需要多少磁盘空间和内存吗?试图找出我的 VPS 需求... 最佳答案 没有最低要求,但我不建议在与您的网络服务器相同的机器上运行 Mongo。 Mon
我的 Django 项目有一个虚拟环境,但是当我 pip 击 pip freeze 时,我得到了一个必须是全局站 pip 包列表的东西,包括太多包,比如ubuntu包和这么多不相关的东西。无论 vir
我曾尝试在 Heroku 上部署我的应用程序,但 smth 出错了。 错误:找不到满足要求的版本 get==2019.4.13(来自 -r/tmp/build_53ad6d03_/requiremen
我无法将 semantic-ui-calendar npm 模块加载到我的应用程序中。 我已经使用脚本标签成功地将它加载到我的 HTML 中, 但每次我尝试将它加载到我的应用程序中时,我都会出错。 在
如何修复 php.ini 中“require”函数内的地址?它进行故障排除并显示错误: 警告:require (..) 无法打开流:没有这样的文件或目录。 文件“db_connection.php”工
我有一个在 Node.js 应用程序中使用的外部库 ( Objection.js )。我创建了一个基本模型类,它为我的实体模型扩展了 Objection 的 Model 类: const { Mode
有谁知道在哪里可以找到RHEL5的GLIBC2.7,如果没有这个,Android模拟器将无法启动。它会给出一条消息,要求GLIBC 2.7或更高版本。 我尝试在网上搜索,但没有找到 最佳答案 我也遇到
Android 设备是否有任何要求/指南?例如按钮数量或所需的最少按钮数量。 还有没有菜单和后退按钮的安卓设备吗? (我知道就可用性而言,没有菜单/后退按钮会杀死大多数应用程序,我只是想了解更多有关该
我想要求/包含一个文件并将其内容检索到一个变量中。 test.php index.php ".$test; ?> 类似于 file_get_contents() 但它仍应执行 PHP 代码。这可能吗
我想要求/包含一个文件并将其内容检索到一个变量中。 test.php index.php ".$test; ?> 类似于 file_get_contents() 但它仍应执行 PHP 代码。这可能吗
我正在尝试在我的 Linux Mint 发行版上安装一个 python 模块“pyAudioProcessing”(https://github.com/jsingh811/pyAudioProces
我已经创建了我的第一个 composer 包,它具有 MySQL 和 MongoDB 的功能,但是,它不需要两者。我意识到有人可能只想将这个包与两个数据库之一一起使用,目前我有: "require":
我想调试以下函数,但假设在调试器中查看 moreajaj 的参数等于什么(假设不像在这个人为的示例中那么明显)是有用的。我可以在调试器框架中打印它,但是在每个参数的每个框架中都这样做很烦人。在宣布每一
我有一些生成的 GNUmakefiles,我需要从中提取变量的值。 有没有一种简单的方法可以在不修改 makefile 的情况下查看变量的值? 仅供引用,变量包含 emacs c-macro-expa
我正在使用 aspell 在 Linux 上拼写检查 LaTeX 文档。我的文档经常包含各种编程语言的代码示例,我希望 aspell 在拼写检查时简单地跳过这些行。 我可以在文档中写些什么来关闭一段文
我有一个包含多个列的数据集... 一列是具有重复值的主石斑鱼列,另一列是具有 bool 值 (1,0) 的 NUMBER,如下所示: grp bool --- ---- A 1 A 1 A
出于测试目的,我正在尝试删除一些 amd 模块并从服务器重新加载更新版本 - 目的是不刷新浏览器。 我目前正在执行以下操作,但浏览器仍然没有从网络重新加载项目。 var scripts = docum
当我键入irb> require 'rubygems'时,它返回false。我的Rails应用程序中有很多 gem ,这些 gem 显然可以正常工作-耙子,activerecord等。这里可能出什么问
我是一名优秀的程序员,十分优秀!