- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我编写了一个小程序来测量循环所花费的时间(通过内联 Sparc 汇编代码片段)。
一切正常,直到我将迭代次数设置为大约 4.0+9(高于 2^32)。
这是代码片段:
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <stdint.h>
int main (int argc, char *argv[])
{
// For indices
int i;
// Set the number of executions
int nRunning = atoi(argv[1]);
// Set the sums
double avgSum = 0.0;
double stdSum = 0.0;
// Average of execution time
double averageRuntime = 0.0;
// Standard deviation of execution time
double deviationRuntime = 0.0;
// Init sum
unsigned long long int sum = 0;
// Number of iterations
unsigned long long int nLoop = 4000000000ULL;
//uint64_t nLoop = 4000000000;
// DEBUG
printf("sizeof(unsigned long long int) = %zu\n",sizeof(unsigned long long int));
printf("sizeof(unsigned long int) = %zu\n",sizeof(unsigned long int));
// Time intervals
struct timeval tv1, tv2;
double diff;
// Loop for multiple executions
for (i=0; i<nRunning; i++)
{
// Start time
gettimeofday (&tv1, NULL);
// Loop with Sparc assembly into C source
asm volatile ("clr %%g1\n\t"
"clr %%g2\n\t"
"mov %1, %%g1\n" // %1 = input parameter
"loop:\n\t"
"add %%g2, 1, %%g2\n\t"
"subcc %%g1, 1, %%g1\n\t"
"bne loop\n\t"
"nop\n\t"
"mov %%g2, %0\n" // %0 = output parameter
: "=r" (sum) // output
: "r" (nLoop) // input
: "g1", "g2"); // clobbers
// End time
gettimeofday (&tv2, NULL);
// Compute runtime for loop
diff = (tv2.tv_sec - tv1.tv_sec) * 1000000ULL + (tv2.tv_usec - tv1.tv_usec);
// Summing diff time
avgSum += diff;
stdSum += (diff*diff);
// DEBUG
printf("diff = %e\n", diff);
printf("avgSum = %e\n", avgSum);
}
// Compute final averageRuntime
averageRuntime = avgSum/nRunning;
// Compute standard deviation
deviationRuntime = sqrt(stdSum/nRunning-averageRuntime*averageRuntime);
// Print results
printf("(Average Elapsed time, Standard deviation) = %e usec %e usec\n", averageRuntime, deviationRuntime);
// Print sum from assembly loop
printf("Sum = %llu\n", sum);
例如,使用 nLoop
< 2^32,我得到了 diff
、avgSum
和 stdSum
的正确值>。事实上,printf
和 nLoop = 4.0e+9
给出:
sizeof(unsigned long long int) = 8
sizeof(unsigned long int) = 4
diff = 9.617167e+06
avgSum = 9.617167e+06
diff = 9.499878e+06
avgSum = 1.911704e+07
(Average Elapsed time, Standard deviation) = 9.558522e+06 usec 5.864450e+04 usec
Sum = 4000000000
代码是在 Debian Sparc 32 位 Etch 上用 gcc 4.1.2
编译的。
不幸的是,如果我以 nLoop = 5.0e+9
为例,我得到的测量时间值很小且不正确;这是这种情况下的 printf 输出:
sizeof(unsigned long long int) = 8
sizeof(unsigned long int) = 4
diff = 5.800000e+01
avgSum = 5.800000e+01
diff = 4.000000e+00
avgSum = 6.200000e+01
(Average Elapsed time, Standard deviation) = 3.100000e+01 usec 2.700000e+01 usec
Sum = 5000000000
我不知道问题出在哪里,我使用 uint64_t
进行了其他测试但没有成功。
也许问题是我使用 32 位操作系统处理 大整数 (> 2^32)
或者它可能是不支持 8 字节整数的汇编内联代码。
按照@AndrewHenle 的建议,我采用了相同的代码,但没有使用内联 Sparc 程序集片段,而是放置了一个简单的循环。
这是带有简单循环的程序,它得到了 nLoop = 5.0e+9
(参见行“unsigned long long int nLoop = 5000000000ULL;
”,所以上面极限 2^32-1
:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <stdint.h>
int main (int argc, char *argv[])
{
// For indices of nRunning
int i;
// For indices of nRunning
unsigned long long int j;
// Set the number of executions
int nRunning = atoi(argv[1]);
// Set the sums
unsigned long long int avgSum = 0;
unsigned long long int stdSum = 0;
// Average of execution time
double averageRuntime = 0.0;
// Standard deviation of execution time
double deviationRuntime = 0.0;
// Init sum
unsigned long long int sum;
// Number of iterations
unsigned long long int nLoop = 5000000000ULL;
// DEBUG
printf("sizeof(unsigned long long int) = %zu\n",sizeof(unsigned long long int));
printf("sizeof(unsigned long int) = %zu\n",sizeof(unsigned long int));
// Time intervals
struct timeval tv1, tv2;
unsigned long long int diff;
// Loop for multiple executions
for (i=0; i<nRunning; i++)
{
// Reset sum
sum = 0;
// Start time
gettimeofday (&tv1, NULL);
// Loop with Sparc assembly into C source
/* asm volatile ("clr %%g1\n\t"
"clr %%g2\n\t"
"mov %1, %%g1\n" // %1 = input parameter
"loop:\n\t"
"add %%g2, 1, %%g2\n\t"
"subcc %%g1, 1, %%g1\n\t"
"bne loop\n\t"
"nop\n\t"
"mov %%g2, %0\n" // %0 = output parameter
: "=r" (sum) // output
: "r" (nLoop) // input
: "g1", "g2"); // clobbers
*/
// Classic loop
for (j=0; j<nLoop; j++)
sum ++;
// End time
gettimeofday (&tv2, NULL);
// Compute runtime for loop
diff = (unsigned long long int) ((tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec));
// Summing diff time
avgSum += diff;
stdSum += (diff*diff);
// DEBUG
printf("diff = %llu\n", diff);
printf("avgSum = %llu\n", avgSum);
printf("stdSum = %llu\n", stdSum);
// Print sum from assembly loop
printf("Sum = %llu\n", sum);
}
// Compute final averageRuntime
averageRuntime = avgSum/nRunning;
// Compute standard deviation
deviationRuntime = sqrt(stdSum/nRunning-averageRuntime*averageRuntime);
// Print results
printf("(Average Elapsed time, Standard deviation) = %e usec %e usec\n", averageRuntime, deviationRuntime);
return 0;
}
此代码片段运行良好,即变量 sum
打印为(参见“printf("Sum = %llu\n", sum)
”):
Sum = 5000000000
所以问题出在带有 Sparc Assembly block 的版本上。
我怀疑,在此汇编代码中,"mov %1, %%g1\n"//%1 = input parameter
行错误地将 nLoop
存储到%g1 register
(我认为 %g1
是一个 32 位寄存器,所以不能存储超过 2^32-1
的值)。
然而,输出参数(变量sum
)在行:
"mov %%g2, %0\n" // %0 = output parameter
高于限制,因为它等于 5000000000。
我在有和没有 Assembly 循环的版本之间附加了 vimdiff :
左边是 With Assembly 编程,右边是 Without Assembly(只是一个简单的循环代替)
我提醒你我的问题是,对于 nLoop > 2^32-1 和汇编循环,我在执行结束时得到一个有效的 sum
参数但无效(太短)average
和 standard deviation
时间(用于循环);下面是 nLoop = 5000000000ULL
的输出示例:
sizeof(unsigned long long int) = 8
sizeof(unsigned long int) = 4
diff = 17
avgSum = 17
stdSum = 289
Sum = 5000000000
diff = 4
avgSum = 21
stdSum = 305
Sum = 5000000000
(Average Elapsed time, Standard deviation) = 1.000000e+01 usec 7.211103e+00 usec
采用nLoop = 4.0e+9
,即nLoop = 4000000000ULL
,没有问题,时间值有效。
我正在通过生成汇编代码进行更深入的搜索。 nLoop = 4000000000 (4.0e+9)
的版本如下:
.file "loop-WITH-asm-inline-4-Billions.c"
.section ".rodata"
.align 8
.LLC1:
.asciz "sizeof(unsigned long long int) = %zu\n"
.align 8
.LLC2:
.asciz "sizeof(unsigned long int) = %zu\n"
.align 8
.LLC3:
.asciz "diff = %llu\n"
.align 8
.LLC4:
.asciz "avgSum = %llu\n"
.align 8
.LLC5:
.asciz "stdSum = %llu\n"
.align 8
.LLC6:
.asciz "Sum = %llu\n"
.global __udivdi3
.global __cmpdi2
.global __floatdidf
.align 8
.LLC7:
.asciz "(Average Elapsed time, Standard deviation) = %e usec %e usec\n"
.align 8
.LLC0:
.long 0
.long 0
.section ".text"
.align 4
.global main
.type main, #function
.proc 04
main:
save %sp, -248, %sp
st %i0, [%fp+68]
st %i1, [%fp+72]
ld [%fp+72], %g1
add %g1, 4, %g1
ld [%g1], %g1
mov %g1, %o0
call atoi, 0
nop
mov %o0, %g1
st %g1, [%fp-68]
st %g0, [%fp-64]
st %g0, [%fp-60]
st %g0, [%fp-56]
st %g0, [%fp-52]
sethi %hi(.LLC0), %g1
or %g1, %lo(.LLC0), %g1
ldd [%g1], %f8
std %f8, [%fp-48]
sethi %hi(.LLC0), %g1
or %g1, %lo(.LLC0), %g1
ldd [%g1], %f8
std %f8, [%fp-40]
mov 0, %g2
sethi %hi(4000000000), %g3
std %g2, [%fp-24]
sethi %hi(.LLC1), %g1
or %g1, %lo(.LLC1), %o0
mov 8, %o1
call printf, 0
nop
sethi %hi(.LLC2), %g1
or %g1, %lo(.LLC2), %o0
mov 4, %o1
call printf, 0
nop
st %g0, [%fp-84]
b .LL2
nop
.LL3:
st %g0, [%fp-32]
st %g0, [%fp-28]
add %fp, -92, %g1
mov %g1, %o0
mov 0, %o1
call gettimeofday, 0
nop
ldd [%fp-24], %o4
clr %g1
clr %g2
mov %o4, %g1
loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bne loop
nop
mov %g2, %o4
std %o4, [%fp-32]
add %fp, -100, %g1
mov %g1, %o0
mov 0, %o1
call gettimeofday, 0
nop
ld [%fp-100], %g2
ld [%fp-92], %g1
sub %g2, %g1, %g2
sethi %hi(999424), %g1
or %g1, 576, %g1
smul %g2, %g1, %g3
ld [%fp-96], %g2
ld [%fp-88], %g1
sub %g2, %g1, %g1
add %g3, %g1, %g1
st %g1, [%fp-12]
sra %g1, 31, %g1
st %g1, [%fp-16]
ldd [%fp-64], %o4
ldd [%fp-16], %g2
addcc %o5, %g3, %g3
addx %o4, %g2, %g2
std %g2, [%fp-64]
ld [%fp-16], %g2
ld [%fp-12], %g1
smul %g2, %g1, %g4
ld [%fp-16], %g2
ld [%fp-12], %g1
smul %g2, %g1, %g1
add %g4, %g1, %g4
ld [%fp-12], %g2
ld [%fp-12], %g1
umul %g2, %g1, %g3
rd %y, %g2
add %g4, %g2, %g4
mov %g4, %g2
ldd [%fp-56], %o4
addcc %o5, %g3, %g3
addx %o4, %g2, %g2
std %g2, [%fp-56]
sethi %hi(.LLC3), %g1
or %g1, %lo(.LLC3), %o0
ld [%fp-16], %o1
ld [%fp-12], %o2
call printf, 0
nop
sethi %hi(.LLC4), %g1
or %g1, %lo(.LLC4), %o0
ld [%fp-64], %o1
ld [%fp-60], %o2
call printf, 0
nop
sethi %hi(.LLC5), %g1
or %g1, %lo(.LLC5), %o0
ld [%fp-56], %o1
ld [%fp-52], %o2
call printf, 0
nop
sethi %hi(.LLC6), %g1
or %g1, %lo(.LLC6), %o0
ld [%fp-32], %o1
ld [%fp-28], %o2
call printf, 0
nop
ld [%fp-84], %g1
add %g1, 1, %g1
st %g1, [%fp-84]
.LL2:
ld [%fp-84], %g2
ld [%fp-68], %g1
cmp %g2, %g1
bl .LL3
nop
ld [%fp-68], %g1
sra %g1, 31, %g1
ld [%fp-68], %g3
mov %g1, %g2
ldd [%fp-64], %o0
mov %g2, %o2
mov %g3, %o3
call __udivdi3, 0
nop
mov %o0, %g2
mov %o1, %g3
std %g2, [%fp-136]
ldd [%fp-136], %o0
mov 0, %o2
mov 0, %o3
call __cmpdi2, 0
nop
mov %o0, %g1
cmp %g1, 1
bl .LL6
nop
ldd [%fp-136], %o0
call __floatdidf, 0
nop
std %f0, [%fp-144]
b .LL5
nop
.LL6:
ldd [%fp-136], %o4
and %o4, 0, %g2
and %o5, 1, %g3
ld [%fp-136], %o5
sll %o5, 31, %g1
ld [%fp-132], %g4
srl %g4, 1, %o5
or %o5, %g1, %o5
ld [%fp-136], %g1
srl %g1, 1, %o4
or %g2, %o4, %g2
or %g3, %o5, %g3
mov %g2, %o0
mov %g3, %o1
call __floatdidf, 0
nop
std %f0, [%fp-144]
ldd [%fp-144], %f8
ldd [%fp-144], %f10
faddd %f8, %f10, %f8
std %f8, [%fp-144]
.LL5:
ldd [%fp-144], %f8
std %f8, [%fp-48]
ld [%fp-68], %g1
sra %g1, 31, %g1
ld [%fp-68], %g3
mov %g1, %g2
ldd [%fp-56], %o0
mov %g2, %o2
mov %g3, %o3
call __udivdi3, 0
nop
mov %o0, %g2
mov %o1, %g3
std %g2, [%fp-128]
ldd [%fp-128], %o0
mov 0, %o2
mov 0, %o3
call __cmpdi2, 0
nop
mov %o0, %g1
cmp %g1, 1
bl .LL8
nop
ldd [%fp-128], %o0
call __floatdidf, 0
nop
std %f0, [%fp-120]
b .LL7
nop
.LL8:
ldd [%fp-128], %o4
and %o4, 0, %g2
and %o5, 1, %g3
ld [%fp-128], %o5
sll %o5, 31, %g1
ld [%fp-124], %g4
srl %g4, 1, %o5
or %o5, %g1, %o5
ld [%fp-128], %g1
srl %g1, 1, %o4
or %g2, %o4, %g2
or %g3, %o5, %g3
mov %g2, %o0
mov %g3, %o1
call __floatdidf, 0
nop
std %f0, [%fp-120]
ldd [%fp-120], %f8
ldd [%fp-120], %f10
faddd %f8, %f10, %f8
std %f8, [%fp-120]
.LL7:
ldd [%fp-48], %f8
ldd [%fp-48], %f10
fmuld %f8, %f10, %f8
ldd [%fp-120], %f10
fsubd %f10, %f8, %f8
std %f8, [%fp-112]
ldd [%fp-112], %f8
fsqrtd %f8, %f8
std %f8, [%fp-152]
ldd [%fp-152], %f10
ldd [%fp-152], %f8
fcmpd %f10, %f8
nop
fbe .LL9
nop
ldd [%fp-112], %o0
call sqrt, 0
nop
std %f0, [%fp-152]
.LL9:
ldd [%fp-152], %f8
std %f8, [%fp-40]
sethi %hi(.LLC7), %g1
or %g1, %lo(.LLC7), %o0
ld [%fp-48], %o1
ld [%fp-44], %o2
ld [%fp-40], %o3
ld [%fp-36], %o4
call printf, 0
nop
mov 0, %g1
mov %g1, %i0
restore
jmp %o7+8
nop
.size main, .-main
.ident "GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)"
.section ".note.GNU-stack"
当我使用 nLoop = 5000000000 (5.0e+9)
生成汇编代码版本时,差异如下图所示(使用 vimdiff
):
“40亿”版本的区 block :
mov 0, %g2
sethi %hi(4000000000), %g3
在“50 亿”版本中被替换为:
mov 1, %g2
sethi %hi(705032192), %g3
or %g3, 512, %g3
我可以看到 5.0+e9
不能在 32 位上编码,因为指令
sethi %hi(705032192), %g3
自相矛盾的是,当我编译版本“5 Billions”汇编代码时,输出参数 sum
计算得很好,即等于 5 Billions
,我可以'不解释了。
最佳答案
很大程度上取决于您使用的 sparc 版本和 ABI。如果您使用的是 sparc v8 或更早版本,则您的 32 位模式只有 32 位寄存器。在这种情况下,当您尝试将 5000000000 加载到 32 位寄存器时,它会失败并改为加载 5000000000 mod 232(即 705032704)。这似乎正在发生。
另一方面,如果您有一个以 32 位模式运行的 64 位 sparc 处理器(通常称为 v8plus),那么您可以使用 64 位寄存器,这样就可以了。
关于c - 在 Sparc 32 位上处理值 > 2^32 的整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45455540/
有没有办法将在 SPARC 上运行的 Solaris 设置为在小端模式下运行? 我一直在读到 v9 架构芯片是双端芯片,但默认情况下,系统以大端运行。如何切换到小端? 谢谢! 最佳答案 不,小端模式几
在过去的几个月里,我一直很好奇尝试为 SPARC 处理器(V8 或 V9)进行一些组装。我的问题是,我无法访问 SPARC 机器,有没有办法可以在我的 x86 机器上运行 SPARC 二进制文件?我看
我安装了 CentOS 7.6,然后在我的机器上安装了所有 QEMU。我有一个 SPARC 镜像,需要在 VM 中调出。我一直在使用 qemu-system-sparc . $ qemu-system
我很少有符合 SPARC V8 32 位架构的基准测试应用程序。我将它们用于 SPARC 32 位处理器的性能评估。然而,很少有应用程序在性能上达不到要求。我想测试 64 位 SPARC V9 架构(
我很少有符合 SPARC V8 32 位架构的基准测试应用程序。我将它们用于 SPARC 32 位处理器的性能评估。然而,很少有应用程序在性能上达不到要求。我想测试 64 位 SPARC V9 架构(
我正在学习 SPARC 程序集,我必须创建一个从寄存器中提取字段的脚本。该脚本接受 3 个值,初始编号、字段开始位置、字段长度。 它不能使用任何移位函数,但可以使用乘法和除法。 我目前患有呼吸道病毒,
我目前正在使用 Sparc 处理器系列的一些汇编代码,但我在处理一段代码时遇到了一些麻烦。我认为代码和输出解释了更多,但简而言之,这是我的问题: 当我调用函数时 println()我写入 %fp -
是否有与 x86 的单步模式等效的 SPARC?我想要的是在每条指令之后停止执行并将控制流移动到陷阱处理程序或类似的东西。 我考虑过在延迟执行槽中使用 ta 指令,但是当前一条指令是设置了 annul
我的 gcc 交叉编译器不支持Built-in functions for atomic memory access 。我如何使用 Sparc V8 架构的内联汇编来实现以下功能: long __sy
我希望我的程序让二进制文件中的每个函数在结束后都留有一些空间。这样一来,如果以后需要进行一些小的更改,则只需更改该功能,而额外的空间将作为解释小更改的空间。 -falign-function 可以完成
java -version 2>&1 |gawk 'NR==1{ gsub(/"/," "); print $3}' 这适用于 Linux 和 Solaris,它将返回该计算机中安装的 Java 版本
我想在我的 C 程序中编写一个什么都不做的非常简单的内联汇编例程否则然后将本地寄存器 %l0 - %l7 设置为不同的值。我尝试了以下直接的方法: asm volatile ( ".text\
我想在 Sparc 中进行一些“内联”汇编编程,我想知道如何通过寄存器传递来做到这一点。 最好用一个小例子来解释我的问题 int main() { int a = 5; int b = 6
我目前正在学习计算机科学,我的必修类(class)之一是“计算机组织和体系结构”——或者换句话说,是汇编语言的介绍。这个特定的类(class)使用 SPARC 语言,因为部门机器只与 SPARC 兼容
我正在开发一个跨平台应用程序,我希望为其提供 Solaris/SPARC 支持,但我无法再访问服务器。我在 VirtualBox 上有一个 OpenSolaris VM,但我不知道有任何可以用来编译和
我有安装了Solaris 10 SPARC的Sun服务器。 我已经使用tarball源代码成功安装了libevent和openssl。我正在尝试使用gnu gmake编译tor-0.2.5.16。我在
所以;在符合 v9 的 64 位 SPARC CPU 上,存在我知道的 cas 指令。这对单个字长值进行操作。 我还在网络上看到了对 casx 指令的引用 - 但我找不到更多关于它的信息。 我想知道
我正在尝试以正确的方式优化此代码。我所说的正确的意思是......我想有一种通用的方法来执行这些优化,如果其他人查看代码,他们将能够删除优化。 可读性的 C 代码示例... int a = 1; //
我想了解为什么使用此代码会出现总线错误。 int main() { int p=34; int *pp= (int *) ((char *)&p+1); cout<<*pp<<"\n"; return
我正在确定函数中的数字是否为零。如果它为零,我需要将一些字符串(如“Is Zero”)传递到我声明为 B 的变量中。我确定它是否为零的函数有效,但是当我尝试使用我的 SPARC 源代码将字符串传递到变
我是一名优秀的程序员,十分优秀!