对于过去的大约。20年来,我一直致力于一个3D图形程序,它实现了一种类似metafont的语言。它是用c++写的。我现在已经开始研究一种格式和函数,用于将3D对象的数据写入二进制文件,然后再次读取它们。它的目的是保存和快速加载已经计算过的数据,以避免每次程序运行时再次计算。
文件格式的语法旨在为一种类似机器的语言提供尽可能高的效率,而不必担心人们读或写是否舒适。
我的问题与数据读入寄存器的方式有关:我的计算机的体系结构是x86_64,所以显然我有64位寄存器。将数据读取到小于64位的对象(即字符、整型或浮点数)中是否值得?难道所有读取的内容都不是读入64位寄存器的吗?据我所知,寄存器中任何未使用的位都被设置为0,这是一个额外的步骤,因此比首先读取长整型或双精度低。这是正确的吗?有人对我应该如何进行有任何建议吗?
这是我对Scheff's Cat的评论的回应。
/* ttemp.c */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void
write_uint(unsigned int i);
void
write_ulong(unsigned long int li);
int fd = 0;
int
main(int argc, char *argv[])
{
printf("Entering ttemp.n");
fd = open("ttemp.output", O_WRONLY | O_CREAT, S_IRWXU);
printf("fd == %dn", fd);
write_uint(~0U);
write_ulong(~0UL);
close(fd);
printf("Exiting ttemp.n");
return 0;
}
void
write_uint(unsigned int i)
{
write(fd, &i, 4);
return;
}
void
write_ulong(unsigned long int li)
{
write(fd, &li, 8);
return;
}
然后我跑了:
gcc -pg -o ttemp ttemp.c
ttemp
gprof ttemp
这是ttemp的内容。根据Emacs在Hexl模式下的输出,所以对象显然被写入了输出文件:
00000000: ffff ffff ffff ffff ffff ffff ............
这是gprof输出的相关部分:
Call graph (explanation follows)
granularity: each sample hit covers 2 byte(s) no time propagated
index % time self children called name
0.00 0.00 1/1 main [8]
[1] 0.0 0.00 0.00 1 write_uint [1]
-----------------------------------------------
0.00 0.00 1/1 main [8]
[2] 0.0 0.00 0.00 1 write_ulong [2]
-----------------------------------------------
所以,不是很有启发性。我的猜测是,寄存器中的空值是在处理器级别执行的,它所花费的任何时间都不会显示在系统调用级别上。然而,我不是一个系统程序员,我对这些主题的把握不是特别牢固。
将数据读取到小于64位的对象(即字符,整型或浮点数)中是否值得?
这取决于体系结构。在大多数平台上,这是非常便宜的,就确切的目标代码而言,即使不是免费的,也只需要一个周期。有关这方面的更多信息,请阅读在64位计算机时代我应该继续使用无符号整型数吗?请注意,float-double转换可能会明显变慢,但在大多数主流x86平台上仍然需要几十个周期(但在嵌入式设备上可能非常慢)。
不是读到64位寄存器的任何东西吗?
实际上,处理器并不是每个64位块读取文件。几乎所有的IO操作都是缓冲的(否则,由于存储设备甚至系统调用的高延迟,它们将非常非常慢)。例如,当您只请求4字节时,系统可以获取256 KiB的缓冲区,因为它知道应用程序经常连续读取文件,也因为大多数存储设备都针对连续操作进行了优化(每秒IO操作的数量通常很小)。有关IO操作与其他操作的延迟的更多信息,请阅读本文(不是数字是近似值)。简而言之,IO操作的延迟远远大于类型转换的延迟,因此后者应该完全可以忽略不计在大多数平台上(至少是所有主流平台)。即使读/写是缓冲的,从内部缓冲区读/写的函数调用的成本仍然高于强制类型转换。因此,在这种情况下,您不应该太在意。