我遇到了一点麻烦。我不确定我是否能理解它。 所以,我有一些代码。我正在尝试为代码中的几个循环添加 #pragma loop(hint_parallel(8)) 语句。 当我使用必要的编译选项编译它时,实际上是这样的:
gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2 -funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp
我遇到段错误。
fish: './a.out' terminated by signal SIGSEGV (Address boundary error)
关键是我不知道为什么会这样。我怀疑这些循环中使用的常量可能有问题。但我不认为这是相关的。如果我只是使用 -O0 优化编译这段代码,它就可以正常工作(因为我猜编译器不会矢量化某些东西)。
能否请您看一下下面的代码,并建议我应该检查哪个方向。 谢谢。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <random>
#include <cstdio>
#include <set>
#include <fstream>
#include <cstdint>
#include <climits>
using namespace std;
const int STRING_HASH_SIZE = 32;
int convert(vector<string> &inputVector, const char **outputArray);
void printCollisions(const char **charArray, int size);
void printArray(const char **arrayToPrint, int size);
int getHashCode(const char *characters, unsigned long size);
string getRandomString();
void writeFileIfNeeded(vector<string> &vector, bool needToWrite);
vector<string> generateStringsVector(int size, bool isNeedToWriteFile);
/**
* main method is present to test these native code.
* to perform some external operation we should use another method.
* @return
*/
int main() {
/**
* The constant represents number of strings that will be generated
* in the string vector generation.
*/
const int STRING_NUMBERS = 100000;
vector<string> inputVector = generateStringsVector(STRING_NUMBERS, false);
#pragma pack 8
const char *charArray[inputVector.size()];
int hashResult = convert(inputVector, charArray);
if (hashResult != 0) {
return 0;
}
printCollisions(charArray, STRING_NUMBERS);
}
/**
* Converts an input vector to char array.
* Getting a hash of
* Returns 0 if conversion from vector to array has been successfully performed.
* @param inputVector [ input array reference ]
* @param outputArray [ a char array that would contain char sequences from vector ]
* @return [ hash sum (int)]
*/
int convert(vector<string> &inputVector, const char **outputArray) {
int hashSum = 0;
#pragma loop(hint_parallel(8))
for (int i = 0; i < inputVector.size(); i++) {
outputArray[i] = inputVector[i].c_str();
}
#pragma loop(hint_parallel(8))
for (auto &i : inputVector) {
hashSum += getHashCode(i.c_str(), i.length());
}
int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
for (int i = 0; i < inputVector.size(); i++) {
hashSum -= getHashCode(outputArray[i], stringHashSize);
}
if (hashSum != 0) {
cout << "\nConversion isn't succeeded, hash = " << hashSum << endl;
} else {
cout << "\nConversion succeeded" << endl;
}
return hashSum;
}
/**
* Prints count and percentage of collisions in array hash codes
* @param charArray
* @param size
*/
void printCollisions(const char **charArray, int size) {
set<int> setOfHashes;
int stringHashSize = STRING_HASH_SIZE;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
setOfHashes.insert(getHashCode(charArray[i], stringHashSize));
}
unsigned long collisions = size - setOfHashes.size();
cout << collisions << "/" << size << " " << 100.0 * collisions / size << "% of collisions";
}
/**
* Prints input char array
* @param arrayToPrint
*/
void printArray(const char **arrayToPrint, int size) {
cout << "\nPrinted array size = " << size << endl;
for (int i = 0; i < size; i++) {
cout << arrayToPrint[i] << ":" << getHashCode(arrayToPrint[i], STRING_HASH_SIZE) << endl;
}
}
/**
*
* @param characters
* @return
*/
int getHashCode(const char *characters, unsigned long size) {
int hash = 0;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
hash = (31 + hash) * (characters[i]);
}
return hash;
}
/**
* Get a random String from alphabetical char sequence.
* @return a randomized string according to an alphabet.
*/
string getRandomString() {
string str("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
random_device rd;
mt19937 generator(rd());
shuffle(str.begin(), str.end(), generator);
return str.substr(0, STRING_HASH_SIZE);
}
/**
* Generates a vector with random strings
* @param size - an int value that will be used as size of a generated vector
* @return reference to generated vector.
*/
vector<string> generateStringsVector(int size, bool isNeedToWriteFile) {
vector<string> charArray;
#pragma loop(hint_parallel(8))
for (int i = 0; i < size; i++) {
string str = getRandomString();
charArray.push_back(str);
}
writeFileIfNeeded(charArray, isNeedToWriteFile);
return charArray;
}
/**
* Writes file with name according to vector size (e.g. 100000.csv)
* if needToWrite is true
* @param vector
* @param needToWrite
*/
void writeFileIfNeeded(vector<string> &vector, bool needToWrite) {
if (needToWrite) {
ofstream csvFile;
string filename = to_string(vector.size()) + ".csv";
csvFile.open(filename, fstream::out);
for (const auto &i : vector) {
csvFile << i << "\n";
}
csvFile.close();
}
}
最佳答案
导致段错误的原因是您编译代码的方式,而不是编译指示(编译指示对 gcc 没有任何影响,见下文):
gcc -w -funroll-loops -O2 -fno-inline -fipa-pta -msse2 -funsafe-math-optimizations -ftree-vectorizer-verbose=1 -fopt-info-optimized=logs/optOpt.txt -shared -fPIC singleThread.cpp
- 通过使用
-shared -fPIC
,您正在创建一个DSO(动态共享对象)。如果您尝试执行此文件,您将得到一个无效的 PC(程序计数器)并且您的程序将立即崩溃。您必须不编译您的代码-shared -fPIC
(如果您需要位置无关的可执行文件<,则使用-pie -fPIE
/em>). - 此外,对于编译 C++ 代码,您通常应该使用
g++
而不是gcc
。 - 给定的编译指示不应对您的代码产生任何影响,因为这些编译指示只能被 Microsoft Visual Studio 理解。将
-Wall
添加到您的编译选项,gcc 将向您显示相应的警告。 - 在任何情况下,您都应该摆脱特定于供应商的 pragma,并改用 OpenMP 等标准化解决方案(使用
-fopenmp
编译)。这样,您离编写独立于编译器的代码又近了一步。 - 至于并行循环,您应该确保不会遇到竞争条件或其他同步失败。例如,要计算总和,
#pragma omp parallel for reduction(+: sum)
是您在 OpenMP 中的 friend (reference sheet)。
免责声明:我在 x86_64 (CentOS Linux) 上使用 gcc 7.3.0。
关于c++ - 添加#pragma loop 后出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50644261/