在Bash中有效地计算浮点运算数十万次

时间:2014-07-02 18:54:21

标签: performance bash shell hpc supercomputers

背景

我在一家研究风暴潮的研究机构工作,并尝试使用Bash自动化一些HPC命令。目前,我们的过程是从NOAA下载数据并逐行手动创建命令文件,输入每个文件的位置以及程序从该文件读取数据的时间和风放大系数。 NOAA生成的每个下载中都有数百个这样的数据文件,当风暴正在进行时,每6个小时左右就会出现一次。这意味着我们在风暴期间的大部分时间都花在制作这些命令文件上。

问题

我可以用来自动化这个过程的工具受限,因为我只是拥有一个用户帐户和每月在超级计算机上分配的时间;我没有权限在他们身上安装新软件。另外,其中一些是Crays,一些是IBM,一些是HP,等等。它们之间没有一致的操作系统;唯一的相似之处是它们都是基于Unix的。所以我拥有像Bash,Perl,awk和Python这样的工具,但不一定是像csh,ksh,zsh,bc等工具:

$ bc
-bash: bc: command not found

此外,我的首席科学家要求我为他写的所有代码都是在Bash中,因为他理解它,只需要很少的外部程序调用Bash就无法做到。例如,它不能做浮点运算,我需要能够添加浮点数。我可以在Bash中调用Perl,但这很慢:

$ time perl -E 'printf("%.2f", 360.00 + 0.25)'
360.25
real    0m0.052s
user    0m0.015s
sys     0m0.015s

1/20分钟看起来好像很长时间,但是当我必须在一个文件中进行100次此调用时,相当于处理一个文件大约需要5秒钟。当我们每6个小时制作其中一个时,这并不是那么糟糕。然而,如果这项工作被抽象为一项更大的任务,我们一次在大西洋盆地指出1,000次合成风暴,以便研究风暴强大或采取不同路径可能发生的事情,5秒迅速增长到只需要一个多小时来处理文本文件。如果按小时计费,则会出现问题。

问题

加快这个速度的好方法是什么?我目前在脚本中有一个for循环(需要5秒才能运行的循环):

for FORECAST in $DIRNAME; do
    echo $HOURCOUNT"  "$WINDMAG"  "${FORECAST##*/} >> $FILENAME;
    HOURCOUNT=$(echo "$HOURCOUNT $INCREMENT" | awk '{printf "%.2f", $1 + $2}');
done

我知道对awk或Perl的单个调用循环数据文件比调用目录中的每个文件一次快一百倍,并且这些语言可以轻松打开文件并写入文件,但是我遇到的问题是来回获取数据。我已经在这三种语言中找到了很多资源(awk,Perl,Python),但是我们还没有找到将它们嵌入到Bash脚本中的更多资源。我能够得到的最接近的是制作一个awk命令的shell:

awk -v HOURCOUNT="$HOURCOUNT" -v INCREMENT="$INCREMENT" -v WINDMAG="$WINDMAG" -v DIRNAME="$DIRNAME" -v FILENAME="$FILENAME" 'BEGIN{ for (FORECAST in DIRNAME) do
    ...
}'

但我不确定这是正确的语法,如果是,如果它是最好的方法,或者它甚至可以工作。我已经在墙上撞了几天了,决定在插上电话之前先上网。

3 个答案:

答案 0 :(得分:3)

只要你具备所需的能力,Bash就非常有能力。对于浮点数,您基本上有两个选项,bc(至少在您显示的框中没有安装[有点难以置信])或calccalc-2.12.4.13.tar.bz2

这两个软件包都是灵活的,非常强大的浮点程序可以很好地与bash集成。由于权力优先于bash,我会调查安装bccalc。 (工作保障是一件好事)

如果可以说服上司允许perlpython,那么其中任何一个都可以。如果你从未编入任何一个,那么两者都会有一个学习曲线python略高于perl。如果您是上级,可以阅读bash,那么翻译perl对于他们来说比python更容易理解。

这是您已经解释过的情况的公平概述。无论您的选择如何,您的任务都不应该是任何语言中令人生畏的。当你遇到困难时,只需退回一条线。

答案 1 :(得分:0)

启动awk或其他命令只是为了做一次添加永远不会有效。 Bash无法处理浮动,因此您需要转移视角。你说你只需要添加花车,我收集这些花车代表一个小时的持续时间。所以请改用秒。

for FORECAST in $DIRNAME; do
    printf "%d.%02d  %s  %s\n" >> $FILENAME \
        $((SECONDCOUNT / 3600)) \
        $(((SECONDCOUNT % 3600) * 100 / 3600)) \
        $WINDMAG \
        ${FORECAST##*/}

    SECONDCOUNT=$((SECONDCOUNT + $SECONDS_INCREMENT))
done

printf是标准的,比格式化输出的echo好得多)

编辑:作为一个函数抽象并带有一些演示代码:

function format_as_hours {
    local seconds=$1
    local hours=$((seconds / 3600))
    local fraction=$(((seconds % 3600) * 100 / 3600))
    printf '%d.%02d' $hours $fraction
}

# loop for 0 to 2 hours in 5 minute steps
for ((i = 0; i <= 7200; i += 300)); do
    format_as_hours $i
    printf "\n"
done

答案 2 :(得分:-2)

如果所有这些计算机都是unices,并且它们需要执行浮点计算,那么每个计算机都必须具有一些支持fp的应用程序。所以复合化合物命令就行了 bc -l some-comp || dc some-comp || ...... || perl some comp