虽然 OP 声称处理 100 个文件需要 12 秒,但我的测量速度要快得多。
TL;DR;
Time for OPs method: 0.006472 seconds
Faster method: 0.005364 seconds
首先,让我们定义衡量指标:我们忽略文件 I/O 所花费的时间,因为在我们关注的实施级别中无法避免它。
我们用这个接口定义数据处理函数:
int testcase (uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen);
然后,我们测量 N 次迭代所花费的时间,为简单起见,我们选择 N=1:
T0 = chrono::system_clock::now();
test_base(des1, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
一旦我们有了更科学的测量结果,我们现在就会对更快的方法有了客观的认识。
但是,我应该指出,没有在所有情况下都最快的通用算法,这就是为什么你有不同的算法。
对于这个特定的测试,我们应该考虑输入样本空间并设计一个处理,以便在统计上针对此类输入样本进行优化。
我假设输入样本是平面英语,因此大多数是 ASCII 字符,并且在小写中,很少有 TAB、SPACE 和换行符;如果不是这样,我的方法会比较慢。
现在,根据上述假设,我会跟踪处理后的字符,并将输出与 memcpy 组合在一起,这在这种特殊情况下会产生稍快的测量。
完整源码:用clang -lstdc++ -O2 a.cpp -o a编译
#include <chrono>
#include <iostream>
#include <unistd.h>
#include <math.h>
using namespace std;
int test_base(uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen) {
int i, j;
if ( deslen < srclen ) return -1;
for (i=0, j=0; i<srclen; ++i) {
switch (src[i]) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
des[j] = src[i] - 32;
++j;
break;
case ' ':
case '\t':
case '\r':
case '\n':
break;
default:
des[j] = src[i];
++j;
}
}
return 0;
}
int testcase_1(uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen) {
const uint8_t* end = src + srclen;
const uint8_t* head = src;
size_t len;
if ( deslen < srclen ) return -1;
for (; src < end; src++) {
uint8_t value = *src;
if ( value >= 'a' && value <='z' ) {
size_t len = (size_t)(src - head);
if ( len > 0 ) memcpy ( des, head, len );
des[len] = value-32;
des += len+1;
head = src+1;
} else if ( value == ' ' || value == '\t' || value == '\r' || value == '\n' ) {
size_t len = (size_t)(src - head);
if ( len > 0 ) memcpy ( des, head, len );
des += len;
head = src+1;
} else {
// Do Nothing
}
}
return 0;
}
int main(int argc, char* argv[]) {
chrono::time_point<chrono::system_clock>T0, T1;
uint64_t duration;
// Create test data
uint8_t *src, *des1, *des2;
const size_t testdata_size = 1024*1024; // 1MB
src = new uint8_t[testdata_size];
des1 = new uint8_t[testdata_size];
des2 = new uint8_t[testdata_size];
// TODO: seed
for ( size_t i=0; i<testdata_size; i++ ) {
src[i] = (uint8_t)rand();
}
// Put things in cache and realize the memory
memset ( des1, 0, testdata_size);
memset ( des2, 0, testdata_size);
T0 = chrono::system_clock::now();
test_base(des1, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
duration = chrono::duration_cast<std::chrono::nanoseconds>(T1-T0).count();
cout << "Duration: " << (duration/1.0E9) << endl;
T0 = chrono::system_clock::now();
testcase_1(des2, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
duration = chrono::duration_cast<std::chrono::nanoseconds>(T1-T0).count();
cout << "Duration: " << (duration/1.0E9) << endl;
if ( memcmp ( des1, des2, testdata_size ) == 0 ) {
cout << "Meaningless compare to prevent optimize!";
}
delete des2;
delete des1;
delete src;
return 0;
}