2013-11-22 55 views
0

所以再次遇到了我無法通過的障礙! 我想解析,加載OpenGL的obj文件!C++改進內存映射obj文件

我已經成功,但它非常慢(用於ifstream) 所以我現在內存映射文件並從那裏解析(加載到內存非常快!)。

問題是我不知道如何保持速度,即使解析它!

目前代碼:

HANDLE file = CreateFile((LPCSTR)loc.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
if(file == INVALID_HANDLE_VALUE) { /* Error handling code! */ } 
HANDLE file2 = CreateFileMapping(file, NULL, PAGE_READONLY, NULL, NULL, (LPCSTR)"CurrentParsingOBJ"); 
VOID* mappedData = MapViewOfFile(file2, FILE_MAP_READ, 0, 0, NULL); 
const char* data = new(mappedData) char[]; 

int i = 0; 
bool v = false, vn = false, vt = false; 
while(*(data + i) != '\0') 
{ 
    if(*(data + i) == '\n') { v = false; vn = false; vt = false; ++i; continue; } 
    if((*(data + i) == 'v' && *(data + i + 1) == ' ') || v) 
    { 
     int a = 0; 
     int p = 0; 
     int pp = 0; 
     v = true; 

    } 
    ++i; 
} 
//Free Mapped Data! 
if(UnmapViewOfFile(mappedData) == NULL) { /* Error handling code! */ } 
mappedData = NULL; 
data = NULL; 

到目前爲止,這是非常不錯的速度! 但我無法弄清楚如何解析它並保持速度! 我已經嘗試了很多解決方案,但所有這些都導致無法接受的速度!

這是我如何與ifstream的做(我想這裏加載相同OBJData結構,內存映射版本藏漢!):

std::ifstream stream(loc); 
if(stream.is_open()) 
{ 
    for(std::string line; std::getline(stream, line);) 
    { 
     if(StringUtil::StringStartsWith(line, "v ")) 
     { 
      Vector3f vec = Vector3f((float)atof((StringUtil::Split(line, ' ')[1])->c_str()), (float)atof((StringUtil::Split(line, ' ')[2])->c_str()), (float)atof((StringUtil::Split(line, ' ')[3])->c_str())); 
      d->V.push_back(vec); 
     }else if(StringUtil::StringStartsWith(line, "vn ")) 
     { 
      Vector3f vec = Vector3f((float)atof((StringUtil::Split(line, ' ')[1])->c_str()), (float)atof((StringUtil::Split(line, ' ')[2])->c_str()), (float)atof((StringUtil::Split(line, ' ')[3])->c_str())); 
      d->VN.push_back(vec); 
     }else if(StringUtil::StringStartsWith(line, "vt ")) 
     { 
      Vector3f vec = Vector3f((float)atof((StringUtil::Split(line, ' ')[1])->c_str()), (float)atof((StringUtil::Split(line, ' ')[2])->c_str()), 0.0F); 
      d->VT.push_back(vec); 
     }else if(StringUtil::StringStartsWith(line, "f ")) 
     { 
      Vector3f vert = Vector3f((float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[1]->c_str(), '/')[0]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[2]->c_str(), '/')[0]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[3]->c_str(), '/')[0]->c_str())); 
      Vector3f norms = Vector3f((float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[1]->c_str(), '/')[2]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[2]->c_str(), '/')[2]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[3]->c_str(), '/')[2]->c_str())); 
      Vector3f textures = Vector3f((float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[1]->c_str(), '/')[1]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[2]->c_str(), '/')[1]->c_str()), (float)atof(StringUtil::Split(StringUtil::Split(line, ' ')[3]->c_str(), '/')[1]->c_str())); 
      d->F.push_back(OBJFace(vert, norms, textures)); 
     } 
    } 
}else { /* Error handling code! */ } 
stream.close(); 

上述版本花費的時間waaay高達1分鐘更大的目標!

所以我的問題:如何在最短的時間內解析「內存映射版本」!並加載與較慢版本相同的OBJData結構!

+1

向我們展示一個小例子輸入。 –

+0

我會發布一些代碼給你看看,這將有望解釋更多比我的描述可能 – GMasucci

+0

你可以做的是避免複製和分配字符串。你可以直接從映射的內存中解析。這會更復雜,但速度更快。 – zch

回答

-1

如果你正在解析很多和/或大文件,或者如果你是第一次解析文件,那麼你很可能是I/O綁定和預取可能會有所幫助。例如,您可能想要啓動一個並行線程,該線程遍歷內存映射文件以便從磁盤獲取它。在C++ 11(未測試):

std::thread prefetch ([data,size]() { 
    volatile char sink = 0; // Volatile should prevent the compiler from optimizing away. 
    for (char* pt = data, end = data + size; pt < end; pt += 1024) sink = *pt; 
}); 
// ... Your parser here ... 
prefetch.join(); 

(Linux的具有MAP_POPULATE flag預取的映射)。

+0

「使用指針會比使用索引快一點」?歡迎回到Powers先生。現在是2013年。自1974年以來,您一直在睡覺。我們現在有真正的編譯器。 –

+0

@Jerry:我沒有睡得那麼久,但對於給定的代碼,索引確實和指針一樣高效(用GCC進行測試),謝謝。 – ArtemGr

+0

當然。你的答案肯定有所改善。 –