X-Authentication-Warning: delorie.com: mailnull set sender to djgpp-bounces using -f From: lbrtchx AT hotmail DOT com (C_CPP_guy) Newsgroups: comp.os.msdos.djgpp Subject: C 67% faster than C++?! Organization: Acecape, Inc. Message-ID: <1009003674.462674@news> Cache-Post-Path: news!unknown AT p66-243 DOT acedsl DOT com X-Cache: nntpcache 2.3.3 (see http://www.nntpcache.org/) Date: 22 Dec 2001 10:43:16 GMT Lines: 539 NNTP-Posting-Host: 7d17cdf5.news.newshosting.com X-Trace: DXC=P^5Z7`[JA=8M`9W3]Vl AT g>X`1N4>^k1L3iF6BbIV4YY2\4CTT1l\<36??2mKW>l_I3 X-Complaints-To: abuse AT newshosting DOT com To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com Hi, cleaning up/rewriting some code from C to C++ I noticed that there was a speed degradation that, to me, was not caused by my coding. The program is I/O intensive. It counts all charaters in a file and saves their offsets and and then checks that the saved values are right. As data feeds I use small and large text and binary files and I used VC++6 as env. , but also tested the code using deloire's djgpp to make sure it was ANSI C/C++. In both cases code was compiled for speed; /O2 compiler option. /nologo /MLd /W3 /Gm /GX /O2 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/std_char_ptr.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /c Here are my questions. Questions: ._ I have always heard local arrays are faster then heap based ones. I tested it and found no difference whatsoever. So, what is it I don't quite understand here? ._ The same algorithm coded in plain ANSI C is 67% faster. Scott Meyers and many other C++ gurus state that there is no or very little, 5%, speed difference between C and C++ programs. What is it I am doing wrong here? ._ Is this the most optimal compiler setting for speed using Win32/VC++? Thanks Camilo Code examples: // - - - - - - - - - - - - - - - C version of program - - - - - - - - - - - - - - - #include #include #include #include // __ #define FLNMLEN 13 // characters needed for file name stringing #define FFLNML 256 // Offset and Segment Info file names length #define ASCIIVOL 256 // ASCII Volume #define SCANBFFR 128 // scan buffer #define BLKLNTGH 8192 // maximal buffer load (cluster size) #define NUMBSNM 32 // Numeric Base used for File Naming #define TSTTP 12 // number of test files #define UTTPLEN sizeof(unsigned int) // sizeof(unsigned int) for writing/reading #define DEBUG_SPOT "\n File=%s, Line#=%d", __FILE__ , __LINE__ struct Chrs{ char azFFlNm[FLNMLEN]; // offset file Name unsigned int utTmsFnd; // times character has been found } chr[ASCIIVOL]; // __ functions signatures void initChrArs(); unsigned int existFl(char* azIsFlThr); void scanFl(char* azPthFlNm); unsigned int checkFl(char* azPthFlNm); // __ int main(void){ unsigned int i, utStrt, utTp; unsigned long ulTtlBytes; double elapsed_time; time_t tm_strt, tm_end, tm_strtAllFls, tm_endAllFls; char* azFls[TSTTP] = {"test00.txt","test04.txt","test06.txt","getty11.txt","USACONST.TXT","alice30h.htm","bible11.txt","winzip80.exe","1donq10.txt","cide.s.txt","j2sdk-1_4_0-beta-win.exe","0xhgp10.txt"}; char azPthFlNm[FFLNML]; char azDir[FFLNML]; FILE* TXTFL; // __ Input Directory, Files and char Buffer strcpy(azDir,"C:/CML/TestFiles/"); // __ Log file time( &tm_strt ); utStrt = 0; utTp = TSTTP; ulTtlBytes = 0; time( &tm_strtAllFls ); // __ array of chars for(i=0; (i < ASCIIVOL); ++i){ itoa(i, chr[i].azFFlNm, NUMBSNM); strcat(chr[i].azFFlNm, ".bin"); }// i time( &tm_strt); // __ for(i=utStrt; (i < utTp); ++i){ strcpy(azPthFlNm, azDir); strcat(azPthFlNm, azFls[i]); if(existFl(azPthFlNm)){ fprintf(stderr, "\n[ %u, %u] Checking: %s", (i - utStrt), (utTp - utStrt - 1), azPthFlNm); scanFl(azPthFlNm); checkFl(azPthFlNm); // __ File Length TXTFL = fopen(azPthFlNm, "rb"); fseek(TXTFL, 0, SEEK_END); ulTtlBytes += ftell(TXTFL); fclose(TXTFL); } time( &tm_end); elapsed_time = difftime( tm_end, tm_strt); fprintf(stderr, "\n %u seconds to process file ", (unsigned int)elapsed_time); tm_strt = tm_end; } initChrArs(); // __ time( &tm_endAllFls); elapsed_time = difftime( tm_endAllFls, tm_strtAllFls); fprintf(stderr, "\n Program takes %f seconds to process %u bytes in all %u files", elapsed_time, ulTtlBytes, (utTp - utStrt)); if(elapsed_time > 0){ fprintf(stderr, "\n, %f (p/s).", (ulTtlBytes/elapsed_time)); } // __ return(0); }// main // __ function bodies // __ void initChrArs(){ unsigned int i; for(i=0; (i < ASCIIVOL); ++i){ chr[i].utTmsFnd = 0; if(existFl(chr[i].azFFlNm)){ if(remove(chr[i].azFFlNm) == -1){ fprintf(stderr, "\n Cannot remove working file %s", chr[i].azFFlNm); fprintf(stderr, DEBUG_SPOT); exit(1); } } }// i } // __ unsigned int existFl(char* azIsFlThr){ unsigned int IsExistFl = 1; FILE* FL; if((FL = fopen(azIsFlThr, "rb"))==NULL){ IsExistFl = 0; } else{ fclose(FL); } return(IsExistFl); } // __ void scanFl(char* azPthFlNm){ unsigned int i, j, utCurFlLngth, utRdByts, utFfst; unsigned int utIxChrAr, utNumBytes; // __ DEBUG unsigned int utChrFndCnt[ASCIIVOL]; // __ heap based arrays unsigned int utFAB[ASCIIVOL][SCANBFFR]; // Offset array buffer unsigned int utFABCnt[ASCIIVOL]; // Offset array buffer count unsigned char ucBytBffr[BLKLNTGH]; // Buffer for read bytes FILE* OFL; FILE* TXTFL = fopen(azPthFlNm, "rb"); // __ File Length fseek(TXTFL, 0, SEEK_END); utCurFlLngth = ftell(TXTFL); fseek(TXTFL, 0, SEEK_SET); // __ initializing initChrArs(); for(i = 0; (i < ASCIIVOL); ++i)utChrFndCnt[i] = 0; for(i = 0; (i < ASCIIVOL); ++i)utFABCnt[i] = 0; utFfst = 0; // __ for(i = 0; (i < ((utCurFlLngth)/BLKLNTGH + 1)); ++i){ utRdByts = (i < ((utCurFlLngth)/BLKLNTGH)) ? BLKLNTGH : (utCurFlLngth % BLKLNTGH); if(utRdByts > 0){ // __ utRdByts = fread( ucBytBffr, sizeof( char ), utRdByts, TXTFL); // __ for(j=0; (j < utRdByts); ++j){ utIxChrAr = (unsigned int)ucBytBffr[j]; if(utFABCnt[utIxChrAr] == SCANBFFR){ // __ appending values OFL = fopen(chr[utIxChrAr].azFFlNm, "ab"); utNumBytes = fwrite( utFAB[utIxChrAr], UTTPLEN, utFABCnt[utIxChrAr], OFL); fclose(OFL); utFABCnt[utIxChrAr] = 0; } utFAB[utIxChrAr][utFABCnt[utIxChrAr]] = utFfst; ++utFABCnt[utIxChrAr]; ++chr[utIxChrAr].utTmsFnd; ++utFfst; // __ ++utChrFndCnt[utIxChrAr]; }// j }// (itRdByts > 0) }//i // __ saving remaining values in buffer for(i = 0; (i < ASCIIVOL); ++i){ if(utFABCnt[i] > 0){ OFL = fopen(chr[i].azFFlNm, "ab"); utNumBytes = fwrite( utFAB[i], UTTPLEN, utFABCnt[i], OFL); fclose(OFL); } } fclose(TXTFL); // __ if(utFfst != utCurFlLngth){ fprintf(stderr, "\n %u =(utFfst != utCurFlLngth)= %u OK!", utFfst, utCurFlLngth); } else{ fprintf(stderr, "\n %u =(utFfst == utCurFlLngth)= %u OK!", utFfst, utCurFlLngth); } } // __ checkFl unsigned int checkFl(char* azPthFlNm){ unsigned int j, k, utCurFlLngth; unsigned int itIsFlOK=1; unsigned int utFnd, utRdByts; unsigned long ulFFlL; int itK, itC; unsigned int itL; unsigned int utFfst; FILE* TXTFL = fopen(azPthFlNm, "rb"); FILE* FDStrm; unsigned long ulBytsCnt; fprintf(stderr, "\n Testing %s", azPthFlNm); // __ File Length fseek(TXTFL, 0, SEEK_END); utCurFlLngth = ftell(TXTFL); fseek(TXTFL, 0, SEEK_SET); // __ Footing of chr[*].utTmsFnd ulBytsCnt = 0; for(j=0; (j < ASCIIVOL); ++j){ if(chr[j].utTmsFnd > 0){ ulBytsCnt += (unsigned long)chr[j].utTmsFnd; } }// j // __ if(ulBytsCnt != utCurFlLngth){ fprintf(stderr, "\n %u=(ulBytsCnt != utCurFlLngth)=%u OK!", ulBytsCnt, utCurFlLngth); itIsFlOK = 0; goto LblEndcheckFl; } else{ fprintf(stderr, "\n %u=(ulBytsCnt == utCurFlLngth)=%u OK!", ulBytsCnt, utCurFlLngth); } // __ Checking offset diffs binary files lengths ulBytsCnt = 0; for(k=0; (k < ASCIIVOL); ++k){ utFnd = chr[k].utTmsFnd; if(utFnd > 0){ FDStrm = fopen(chr[k].azFFlNm, "rb"); // __ File Length fseek(FDStrm, 0, SEEK_END); ulFFlL = (unsigned long)ftell(FDStrm); fseek(FDStrm, 0, SEEK_SET); if(utFnd != (unsigned int)(ulFFlL/4)){ fprintf(stderr, "\n k=%u, %u=(utFnd != (ulFFlL/4))=%u, %s\n", k, utFnd, (ulFFlL/4), chr[k].azFFlNm); exit(1); } ulBytsCnt += ulFFlL; fclose(FDStrm); }// (utFnd > 0) }// k // __ if((ulBytsCnt/4) == utCurFlLngth){ fprintf(stderr, "\n All offset files lengths tested OK!"); } else{ fprintf(stderr, "\n ~* all offset files DID NOT test OK!"); itIsFlOK = 0; goto LblEndcheckFl; } // __ Checking all bytes ulBytsCnt = 0; for(itK=0; (itK < (int)ASCIIVOL); ++itK){ if(chr[itK].utTmsFnd > 0){ FDStrm = fopen(chr[itK].azFFlNm, "rb"); ulBytsCnt += (unsigned long)chr[itK].utTmsFnd; for(itL=0; (itL < chr[itK].utTmsFnd) && (itIsFlOK == 1); ++itL){ utRdByts = fread( &utFfst, UTTPLEN, 1, FDStrm); fseek(TXTFL, utFfst, SEEK_SET); itC = getc(TXTFL); if(itC != itK){ fprintf(stderr, "\n (itC=%d != %d=itK) %c, itL=%d, chr[itK].utTmsFnd=%u, utFfst=%u", itC, itK, (char)itK, itL, chr[itK].utTmsFnd, utFfst); itIsFlOK = 0; exit(1); goto LblNxtLoop; // Check all of them temporarily }// (itC != itK) }// itL LblNxtLoop:; fclose(FDStrm); }// (chr[itK].utTmsFnd > 0) }// itK fprintf(stderr, "\n ulBytsCnt=%u, utCurFlLngth=%u", ulBytsCnt, utCurFlLngth); if(ulBytsCnt == utCurFlLngth){ fprintf(stderr, "\n All byte counts tested OK!"); } else{ fprintf(stderr, "\n NOT all byte counts tested OK."); itIsFlOK = 0; } fclose(TXTFL); LblEndcheckFl: return(itIsFlOK); } // - - - - - - - - - - - - - - - C++ version of program - - - - - - - - - - - - - - - #include #include #include #include #include #include using namespace std; // __ const unsigned int FLNMLEN = 13; // characters needed for file name stringing const unsigned int FLNMBF = 256; // file name buffer for input files. OS dependent const unsigned int ASCIIVOL = 256; // ASCII Volume const unsigned int SCANBFFR = 128; // scan buffer. # of values cached before batch saving onto offset files const unsigned int BLKLNTGH = 8192; // maximal buffer for characters read at once (cluster size) const unsigned int NUMBSNM = 32; // Numeric Base used for File Naming const unsigned int TSTTP = 12; // number of test files const unsigned int UTTPLEN = sizeof(unsigned int); // sizeof(unsigned int) for writing/reading #define DEBUG_SPOT "\n File=" << __FILE__ << ", Line#=" << __LINE__ << endl // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * class FileChars{ private: // __ struct Chrs{ char azFFlNm[FLNMLEN]; // offset file Name unsigned int utTmsFnd; // times character has been found } chr[ASCIIVOL]; // __ char* azPthFlNm; // Current File Name unsigned int utCurFlLngth; // Current File Length // __ unsigned int existFl(const char* azIsFlThr){ unsigned int IsExistFl = 1; ifstream ifFDStrm; ifFDStrm.open(azIsFlThr, ios::in|ios::binary); if(ifFDStrm.fail()){ IsExistFl = 0; } else{ ifFDStrm.close(); } return(IsExistFl); } // __ void initChrArs(){ unsigned int i; for(i=0; (i < ASCIIVOL); ++i){ chr[i].utTmsFnd = 0; if(existFl(chr[i].azFFlNm)){ if(remove(chr[i].azFFlNm) == -1){ cerr << " Cannot remove working file " << chr[i].azFFlNm << DEBUG_SPOT << endl; exit(1); } } }// i } // __ public: // __ FileChars(){ unsigned int i; for(i=0; (i < ASCIIVOL); ++i){ itoa(i, chr[i].azFFlNm, NUMBSNM); strcat(chr[i].azFFlNm, ".bin"); } }// FileChars // __ ~FileChars(){ initChrArs(); } // __ void setFl(char* azPthFlNm){ this->azPthFlNm = azPthFlNm; } // __ unsigned int getCurFlLngth(){ return(this->utCurFlLngth); } // __ void scanFl(){ ifstream ifTxtStrm; ifTxtStrm.open(this->azPthFlNm, ios::in|ios::binary); // __ File Length ifTxtStrm.seekg(0, ios::end); this->utCurFlLngth = (unsigned int)ifTxtStrm.tellg(); ifTxtStrm.seekg(0, ios::beg); // __ if(!ifTxtStrm.fail()){ ofstream OStrm; unsigned int i, j, utRdByts, utFfst = 0; unsigned int utIxChrAr; // __ DEBUG ifstream IStrm; unsigned int utChrFndCnt[ASCIIVOL]; for(i = 0; (i < ASCIIVOL); ++i)utChrFndCnt[i] = 0; // __ heap based arrays unsigned int** utFA; // Offset array buffer utFA = new unsigned int*[ASCIIVOL]; for(i = 0; (i < ASCIIVOL); ++i){ utFA[i] = new unsigned int[SCANBFFR]; } unsigned int* utFABCnt = new unsigned int[ASCIIVOL]; // Offset array buffer count unsigned char* ucBytBffr = new unsigned char[BLKLNTGH]; // Buffer for read bytes // __ initializing for(i = 0; (i < ASCIIVOL); ++i)utFABCnt[i] = 0; utFfst = 0; initChrArs(); // __ for(i = 0; (i < ((utCurFlLngth)/BLKLNTGH + 1)); ++i){ utRdByts = (i < ((utCurFlLngth)/BLKLNTGH)) ? BLKLNTGH : (utCurFlLngth % BLKLNTGH); if(utRdByts > 0){ ifTxtStrm.read(reinterpret_cast (ucBytBffr), utRdByts); for(j=0; (j < utRdByts); ++j){ utIxChrAr = (unsigned int)ucBytBffr[j]; if(utFABCnt[utIxChrAr] == SCANBFFR){ OStrm.open(chr[utIxChrAr].azFFlNm, ios::out|ios::binary|ios::app); OStrm.write(reinterpret_cast (utFA[utIxChrAr]), UTTPLEN*SCANBFFR); OStrm.close(); utFABCnt[utIxChrAr] = 0; } utFA[utIxChrAr][utFABCnt[utIxChrAr]] = utFfst; ++utFABCnt[utIxChrAr]; ++chr[utIxChrAr].utTmsFnd; ++utFfst; // __ ++utChrFndCnt[utIxChrAr]; }// j }// (itRdByts > 0) }//i // __ saving remaining values in buffer for(i = 0; (i < ASCIIVOL); ++i){ if(utFABCnt[i] > 0){ OStrm.open(chr[i].azFFlNm, ios::out|ios::binary|ios::app); if(!OStrm.fail()){ OStrm.write(reinterpret_cast (utFA[i]), UTTPLEN*utFABCnt[i]); OStrm.close(); } else{ cerr << " OStrm.fail()=" << OStrm.fail() << endl; exit(1); } } } ifTxtStrm.close(); // __ Cleaning after/deleting arrays delete[] ucBytBffr; delete[] utFABCnt; // __ deleting two dimensional array for(i = 0; (i < ASCIIVOL); ++i)delete[] utFA[i]; // deleting second 'unsigned int[SCANBFFR]' dimension delete[] utFA; if(utFfst != utCurFlLngth){ cerr << utFfst << " (utFfst != utCurFlLngth) " << utCurFlLngth << endl; } else{ cerr << utFfst << " (utFfst == utCurFlLngth) " << utCurFlLngth << " OK!" << endl; } } else{ cerr << " Could not open file: " << azPthFlNm << endl; } }// scanFl // __ checkFl unsigned int checkFl(){ unsigned int j, k; unsigned int itIsFlOK=1; ifstream ifTxtStrm, ifFDStrm; unsigned long ulBytsCnt; cerr << " Testing " << azPthFlNm << endl; ifTxtStrm.open(this->azPthFlNm, ios::in|ios::binary); if(!ifTxtStrm.fail()){ // __ File Length ifTxtStrm.seekg(0, ios::end); unsigned int utCurFlLngth = (unsigned int)ifTxtStrm.tellg(); ifTxtStrm.seekg(0, ios::beg); // __ Footing of chr[*].utTmsFnd ulBytsCnt = 0; for(j=0; (j < ASCIIVOL); ++j){ if(chr[j].utTmsFnd > 0){ ulBytsCnt += (unsigned long)chr[j].utTmsFnd; } }// j // __ if(ulBytsCnt != utCurFlLngth){ cerr << ulBytsCnt << "= (ulBytsCnt != utCurFlLngth) =" << utCurFlLngth << endl; itIsFlOK = 0; exit(1); goto LblEndcheckFl; } else{ cerr << ulBytsCnt << "= (ulBytsCnt == utCurFlLngth) =" << utCurFlLngth << ", OK!" << endl; } // __ Checking offset diffs binary files lengths ulBytsCnt = 0; unsigned int utFnd; unsigned long ulFFlL; for(k=0; (k < ASCIIVOL); ++k){ utFnd = chr[k].utTmsFnd; if(utFnd > 0){ ifFDStrm.open(chr[k].azFFlNm,ios::in|ios::binary); if(!ifFDStrm.fail()){ ifFDStrm.seekg(0, ios::end); ulFFlL = (unsigned long)ifFDStrm.tellg(); if(utFnd != (unsigned int)(ulFFlL/4)){ cerr << "(" << k << "," << (unsigned char)k << "), utFnd=" << utFnd << " != " << (ulFFlL/4) << "=(ulFFlL/4)" << endl; } ulBytsCnt += ulFFlL; ifFDStrm.close(); } }// (utFnd > 0) }// k // __ if((ulBytsCnt/4) == utCurFlLngth){ cerr << " All offset files lengths tested OK!" << endl; } else{ cerr << " ~* all offset files DID NOT test OK!" << endl; } // __ Checking all bytes int itK, itC; unsigned int itL; unsigned int utFfst; ulBytsCnt = 0; for(itK=0; (itK < (int)ASCIIVOL); ++itK){ if(chr[itK].utTmsFnd > 0){ ifFDStrm.open(chr[itK].azFFlNm, ios::in|ios::binary); ulBytsCnt += (unsigned long)chr[itK].utTmsFnd; for(itL=0; (itL < chr[itK].utTmsFnd) && (itIsFlOK == 1); ++itL){ ifFDStrm.read(reinterpret_cast (&utFfst), UTTPLEN); ifTxtStrm.seekg(utFfst); itC = ifTxtStrm.get(); if(itC != itK){ cerr << "(itC=" << itC << "!=" << itK << "=itK)" << " itL=" << itL << "," << chr[itK].utTmsFnd << ", utFfst=" << utFfst << ", itC=" << itC << ", itK=" << itK << endl; exit(1); goto LblNxtLoop; // Check all of them temporarily }// (itC != itK) }// itL LblNxtLoop:; ifFDStrm.close(); }// (chr[itK].utTmsFnd > 0) }// itK cerr << " ulBytsCnt=" << ulBytsCnt << ", utCurFlLngth=" << utCurFlLngth << endl; if(ulBytsCnt == utCurFlLngth){ cerr << " All bytes offsets tested OK!" << endl; } else{ cerr << " NOT all bytes offsets tested OK." << endl; itIsFlOK = 0; } ifTxtStrm.close(); } else{ cerr << " Could not open file" << azPthFlNm << endl; itIsFlOK = 0; } LblEndcheckFl: return(itIsFlOK); } }; int main(void){ unsigned int i, utStrt, utTp; unsigned long ulTtlBytes; double elapsed_time; time_t tm_strt, tm_end, tm_strtAllFls, tm_endAllFls; // __ Input Directory, Files and char Buffer char azDir[FLNMBF]; strcpy(azDir,"C:/CML/TestFiles/"); const char* azFls[TSTTP] = {"test00.txt","test04.txt","test06.txt","getty11.txt","USACONST.TXT","alice30h.htm","bible11.txt","winzip80.exe","1donq10.txt","cide.s.txt","j2sdk-1_4_0-beta-win.exe","0xhgp10.txt"}; char azPthFlNm[FLNMBF]; // __ Log file time( &tm_strt ); utStrt = 0; utTp = TSTTP; ulTtlBytes = 0; time( &tm_strtAllFls ); FileChars* FlChrs = new FileChars(); time( &tm_strt); for(i=utStrt; (i < utTp); ++i){ strcpy(azPthFlNm, azDir); strcat(azPthFlNm, azFls[i]); cerr << "[" << i << "," << (utTp - utStrt - 1) << "] Checking: " << azPthFlNm << endl; FlChrs->setFl(azPthFlNm); FlChrs->scanFl(); FlChrs->checkFl(); ulTtlBytes += FlChrs->getCurFlLngth(); time( &tm_end); elapsed_time = difftime( tm_end, tm_strt); cerr << elapsed_time << " seconds to process file " << endl; tm_strt = tm_end; } delete FlChrs; // __ time( &tm_endAllFls); elapsed_time = difftime( tm_endAllFls, tm_strtAllFls); cerr << " Program takes " << elapsed_time << " seconds to process " << ulTtlBytes << " bytes in all " << (utTp - utStrt) << " files"; if(elapsed_time > 0){ cerr << ", " << (ulTtlBytes/elapsed_time) << " (p/s)." << endl; } // __ return(0); }// main