我正在尝试优化this challenge的解决方案。在注意到其他解决方案之一使用了一个很好的技巧 - 将size
更改为编译时模板参数后,我想检查自己如何加速代码。
我正在使用Release配置从MSVC2013进行编译。这是原始代码:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using std::cout;
using std::endl;
typedef std::vector<char*> Board;
int size;
void rotate(char *str){
char temp = str[0];
str[0] = str[1];
str[1] = str[2];
str[2] = str[3];
str[3] = temp;
}
inline char fastToLower(char c){ //actually it's toUpper but whatever
return (c - 65) % 32;
}
bool checkLeftEdge(Board::iterator begin, Board::iterator right){
if ((right - begin) % size == 0)
return true;
auto left = right - 1;
char c1 = (*right)[3], c2 = (*left)[1];
return fastToLower(c1) == fastToLower(c2) && c1 != c2;
}
bool checkTopEdge(Board::iterator begin, Board::iterator bottom){
auto top = bottom - size;
if (top < begin)
return true;
char c1 = (*bottom)[0], c2 = (*top)[2];
return fastToLower(c1) == fastToLower(c2) && c1 != c2;
}
bool isLastElementValid(Board::iterator begin, Board::iterator last){
return
checkTopEdge(begin, last) &&
checkLeftEdge(begin, last);
}
bool recurse(Board::iterator begin, Board::iterator end, Board::iterator len){
if (len == end)
return true;
for (auto it = len; it != end; ++it){
std::swap(*len, *it);
for (int j = 0; j < 4; ++j){
if (isLastElementValid(begin, len)){
bool ret = recurse(begin, end, len + 1);
if (ret == true)
return ret;
}
rotate(*len);
}
std::swap(*len, *it);
}
return false;
}
void draw(const Board &board){
for (int y = 0; y < size; ++y){
cout << std::string(size * 4 + 1, '-') << endl;
for (int x = 0; x < size; ++x)
cout << "| " << board[to_index(x, y)][0] << " ";
cout << "|" << endl;
for (int x = 0; x < size; ++x)
cout << "|" << board[to_index(x, y)][3] << " " << board[to_index(x, y)][1];
cout << "|" << endl;
for (int x = 0; x < size; ++x)
cout << "| " << board[to_index(x, y)][2] << " ";
cout << "|" << endl;
}
cout << std::string(size * 4 + 1, '-') << endl;
cout << endl;
}
int main(){
std::ifstream in ("in.txt");
if (!in)
return 1;
in >> size;
Board board(size * size);
for (auto& ptr : board){
ptr = new char[4];
in.ignore();
in.read(ptr, 4);
}
auto success = recurse(board.begin(), board.end(), board.begin());
if (success)
draw(board);
for (auto& ptr : board)
delete []ptr;
std::cin.ignore();
std::cin.get();
}
使用这组样本数据:
5
ckck
yYcc
YcCK
kKCM
CMKc
cKYC
kYcm
KYyY
Mccm
yKcm
mykK
MMCm
ckYC
ycmm
MmKM
kymc
KMMK
KcyM
kYck
YCKM
myYm
kYyY
CMKM
yYCM
YKyk
程序运行了11.5秒。
当我更换
bool checkTopEdge(Board::iterator begin, Board::iterator bottom){
auto top = bottom - size;
带
auto top = bottom - 5;
该程序运行了不到10秒。
但是当我更换时:
bool checkLeftEdge(Board::iterator begin, Board::iterator right){
if ((right - begin) % size == 0)
与
if ((right - begin) % 5 == 0)
时间增加到16秒!
我已经看了一下反汇编,并注意到isLastElementValid
函数不再内联,尽管checkLeftEdge
和checkTopEdge
仍然是。
代码的修改部分似乎没有太大变化:
0138136C mov eax,ecx
0138136E sub eax,esi
01381370 sar eax,2
01381373 cdq
01381374 idiv eax,ebx
01381376 test edx,edx
01381378 je recurse+0E2h (013813B2h)
有5个字面:
00B4133D mov eax,ecx
00B4133F mov esi,5
00B41344 sub eax,edx
00B41346 sar eax,2
00B41349 cdq
00B4134A idiv eax,esi
00B4134C test edx,edx
00B4134E je isLastElementValid+0CAh (0B4139Ah)
所以我的问题是:我没有看到我所做的更改是如何导致程序变慢的。即使MSVC出于某种原因决定不再列出其中一项功能,我也无法相信这一点会导致运行时间增加50%。
答案 0 :(得分:1)
这实际上是由linining引起的。我已经通过将__declspec(noinline)
添加到isLastElementValid来检查,这确实造成了50%的损失。
使用__forceinline
强制内联解决了我的问题。