计算在Linux上用c ++复制二进制文件所花费的时间的最佳方法是什么?#34;?

时间:2014-02-11 21:45:47

标签: c++ linux

我使用以下代码复制大小约为1.1 GB的文件

#include <iostream>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctime>
using namespace std;
int main ()
{
 clock_t start, end;
    start = clock();
 int read_fd;
 int write_fd;
 struct stat stat_buf;
 off_t offset = 0;

 /* Open the input file. */
 read_fd = open ("source", O_RDONLY);
 /* Stat the input file to obtain its size. */
 fstat (read_fd, &stat_buf);
 /* Open the output file for writing, with the same permissions as the
   source file. */
 write_fd = open ("destination", O_WRONLY | O_CREAT, stat_buf.st_mode);
 /* Blast the bytes from one file to the other. */
 sendfile (write_fd, read_fd, &offset, stat_buf.st_size);
 /* Close up. */
 close (read_fd);
 close (write_fd);
  end = clock();

    cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << "\n";
    cout << "CPU-TIME START " << start << "\n";
    cout << "CPU-TIME END " << end << "\n";
    cout << "CPU-TIME END - START " <<  end - start << "\n";
    cout << "TIME(SEC) " << static_cast<double>(end - start) / CLOCKS_PER_SEC << "\n";

 return 0;
}

输出是:

   CLOCKS_PER_SEC 1000000 
CPU-TIME START 0 CPU-TIME END 6140000
 CPU-TIME END - START 6140000 TIME(SEC) 6.14

但是,当我实际计算时间时,它(复制)需要大约84秒的时间!!! 现在我将在下面的代码中使用“structure timeval”,输出为:83 456677它与实际时间几乎相同。

#include <iostream>
#include <sys/sendfile.h>  // sendfile
#include <fcntl.h>         // open
#include <unistd.h>        // close
#include <sys/stat.h>      // fstat
#include <sys/types.h>     // fstat
#include <ctime>
extern "C" {
 #include <sys/time.h>
 }
#include <stdio.h>
using namespace std;

int main() {
   struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL); 

    int source = open("source", O_RDONLY, 0);
    int dest = open("distination", O_WRONLY | O_CREAT /*| O_TRUNC/*/, 0644);

    // struct required, rationale: function stat() exists also
    struct stat stat_source;
    fstat(source, &stat_source);

    sendfile(dest, source, 0, stat_source.st_size);

    close(source);
    close(dest);

  gettimeofday(&endTV, NULL); 

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

    return 0;
}

然后我将使用'pv source&gt; destination'a命令然后输出为1.02e+03MB 0:01:24 [12.1MB/s] [===========================>] 100%,它与实际时间相同。

此外,当我以图形模式(普通复制/粘贴)复制文件时,需要大约84秒的时间。

问题

  1. 以第一种方式计算的时间是多少?
  2. 'pv'或Pipe Viewer,是否正确显示了OS复制文件所需的时间?
  3. 请总结一下,sendfile()复制所用的时间与OS几乎相同?

2 个答案:

答案 0 :(得分:1)

  

以第一种方式计算的时间是多少?

这是您的程序花在使用CPU上的时间。 clock()测量CPU时间。复制文件 通常花费大部分时间做其他事情(I / O,例如等待硬盘移动或响应,等待内核中的锁定,等等。)。

  

'pv'或Pipe Viewer是否正确显示了OS复制文件所需的时间?

它显示从收到第一个字节到收到最后一个字节所花费的时间。

请记住,写入文件通常只是写入文件系统缓存,因此它只是写入RAM。操作系统会在闲暇时将该缓存刷新到驱动器,这可能是在您的程序,cp程序或您使用的任何GUI文件管理器之后表示复制已完成。 (这不是真正的问题,除非你切断电源,从你复制的文件读取通过相同的缓存)。

如果要确保将数据刷新到驱动器,请在文件描述符上调用fdatasync()。

这也意味着您可以轻松地测量复制文件的不同时间。如果文件或其中的一部分恰好驻留在文件系统缓存中,那么您正在从RAM中读取。如果它不在缓存中,则需要从驱动器中读取,这可能要慢一两个数量级。

  

我们总结一下,sendfile()复制所用的时间与OS几乎相同吗?

对不起,我不知道你在这里问的是什么..

答案 1 :(得分:0)

不是您问题的直接答案,但您可能会发现strace -T非常有用,除非您绝对需要在您的程序中存储统计信息。

测试

$  cat /dev/urandom > chunk.bin
^C
$  strace -T cp -p chunk.bin dust.bin

输出(参见每个系统调用后三角括号中的数字)

stat("dust.bin", 0x7fff747c5640)        = -1 ENOENT (No such file or directory) <0.000303>
stat("chunk.bin", {st_mode=S_IFREG|0664, st_size=19202048, ...}) = 0 <0.000341>
stat("dust.bin", 0x7fff747c5290)        = -1 ENOENT (No such file or directory) <0.000281>
open("chunk.bin", O_RDONLY)             = 3 <0.000272>
fstat(3, {st_mode=S_IFREG|0664, st_size=19202048, ...}) = 0 <0.000272>
open("dust.bin", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4 <0.000404>
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 <0.000272>
read(3, "\216\330A\27J\373\1a\10\262&\221B\255\271\227\342:\252?\334\3169a\212\27\205=+\300\273\370"..., 32768) = 32768 <0.000684>
write(4, "\216\330A\27J\373\1a\10\262&\221B\255\271\227\342:\252?\334\3169a\212\27\205=+\300\273\370"..., 32768) = 32768 <0.000359>
read(3, "\327\344\343|\243\247\211\200\211\212\331\247WF\324\33\276\317\241[{\24\354D\223\215\332\247\34\376\246W"..., 32768) = 32768 <0.000494>
write(4, "\327\344\343|\243\247\211\200\211\212\331\247WF\324\33\276\317\241[{\24\354D\223\215\332\247\34\376\246W"..., 32768) = 32768 <0.000379>
...
read(3, "", 32768)                      = 0 <0.000226>
utimensat(4, NULL, {{1392157379, 551638340}, {1392157405, 783308564}}, 0) = 0 <0.000254>
fgetxattr(3, "system.posix_acl_access", 0x7fff747c4f50, 132) = -1 ENODATA (No data available) <0.000234>
fstat(3, {st_mode=S_IFREG|0664, st_size=19202048, ...}) = 0 <0.000223>
fsetxattr(4, "system.posix_acl_access", "\x02\x00\x00\x00\x01\x00\x06\x00\xff\xff\xff\xff\x04\x00\x06\x00\xff\xff\xff\xff \x00\x04\x00\xff\xff\xff\xff", 28, 0) = 0 <0.000285>
close(4)                                = 0 <0.000250>
close(3)                                = 0 <0.000267>