/** * @file test1.cpp * @brief 文字列表示での文字列処理の時間計測. */ #include <stddef.h> #include <cstddef> #include <stdlib.h> #ifdef MALLOC_CHK #include "malloc_chk.h" #endif #include <stdio.h> #include <assert.h> #include <string.h> #include <string> #include <streambuf> #include <sstream> #include <strstream> #ifdef _WIN32 #include <windows.h> #ifdef USE_WTL #include <atlbase.h> #include <atlapp.h> #include <atlmisc.h> using namespace WTL; #endif #endif #include "StrzStream.h" using namespace std; // =========================================================================== // 時間計測関係 #ifdef _WIN32 #include <windows.h> typedef unsigned __int64 PerfCnt_tick_t; PerfCnt_tick_t PerfCnt_getTick() { PerfCnt_tick_t c; QueryPerformanceCounter((LARGE_INTEGER*)&c); return c; } PerfCnt_tick_t PerfCnt_tickPerSec() { static PerfCnt_tick_t s = 0; if (!s) QueryPerformanceFrequency((LARGE_INTEGER*)&s); return s; } #elif defined LINUX #include <sys/resource.h> typedef double PerfCnt_tick_t; PerfCnt_tick_t PerfCnt_getTick() { struct rusage t; getrusage(RUSAGE_SELF, &t); return t.ru_utime.tv_sec * 1000000.0 + t.ru_utime.tv_usec; } #define PerfCnt_tickPerSec() 1000000.0 #else #include <time.h> typedef clock_t PerfCnt_tick_t; #define PerfCnt_getTick() clock() #define PerfCnt_tickPerSec() CLOCKS_PER_SEC #endif // =========================================================================== void dummy_puts(const char* msg); // 空関数だが最適化させないため、別ファイル. void dummy_puts_set_mode(int mode); // sprintfを使った場合. void test_sprintf(const char* msg, const char* fname, unsigned line) { char buf[1024]; sprintf(buf, "%s(%d) : test> %s", fname, line, msg); dummy_puts(buf); } // ポインタやmemcpy等でメッセージ生成. void test_memcpy(const char* msg, const char* fname, unsigned line) { char buf[1024]; unsigned l = strlen(fname); char* p = (char*)memcpy(buf, fname, l); p += l; *p++ = '('; ltoa(line, p, 10); p += strlen(p); memcpy(p, ") : test> ", 10); p += 10; memcpy(p, msg, strlen(msg)+1); dummy_puts(buf); } // strcpy,strcatで楽にメッセージ生成. void test_strcat(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); char buf[1024]; strcpy(buf, fname); strcat(buf, "("); strcat(buf, lineBuf); strcat(buf, ") : test> "); strcat(buf, msg); dummy_puts(buf); } #if 1 // std::string で楽に書いた場合. void test_std_string(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); dummy_puts((std::string(fname) + '(' + lineBuf + ") : test> " + msg).c_str() ); } // std::string でなるべくアロケートが発生しないように書いた場合. void test_std_string_rsv(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); std::string str; str.reserve(1024); str += fname; str += '('; str += lineBuf; str += ") : test> "; str += msg; dummy_puts( str.c_str() ); } static std::string s_str; void init_test_std_string_static() { s_str.reserve(1024); } // std::string で予め変数(メモリ)確保して、表示時のアロケートをたぶん無くした場合. void test_std_string_static(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); std::string& rStr = s_str; rStr.clear(); rStr += fname; rStr += '('; rStr += lineBuf; rStr += ") : test> "; rStr += msg; dummy_puts( rStr.c_str() ); } #endif #ifdef USE_WTL // WTL::CString で、楽に書いた場合. void test_ms_cstring(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); dummy_puts( CString(fname) + '(' + lineBuf + ") : test> " + msg ); } // WTL::CString で、メモリ確保して順に足した場合. void test_ms_cstring_rsv(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); CString str; str.GetBuffer(1024); str += fname; str += '('; str += lineBuf; str += ") : test> "; str += msg; dummy_puts( str ); } /* // CStringのメモリ管理的に、メリットがなかったので破棄. static CString s_cstring; void init_test_ms_cstring_static() {s_cstring.GetBuffer(1024);} void test_ms_cstring_static(const char* msg, const char* fname, unsigned line) { char lineBuf[32]; ltoa(line, lineBuf, 10); CString& rStr = s_cstring; // rStr.Empty(); rStr += fname; rStr += '('; rStr += lineBuf; rStr += ") : test> "; rStr += msg; dummy_puts( rStr ); } */ // WTL::CString のFormatで指定した場合. void test_ms_cstring_format(const char* msg, const char* fname, unsigned line) { CString str; str.Format("%s(%d) : test> %s", fname, line, msg); dummy_puts( str ); } #endif // USE_WTL // stringstream を使った場合. void test_stringstream_local(const char* msg, const char* fname, unsigned line) { stringstream ss; ss << fname << '(' << line << ") : test> " << msg; dummy_puts( ss.str().c_str() ); } static stringstream s_stringstream; // stringstream を予め生成して使った場合. void test_stringstream_static(const char* msg, const char* fname, unsigned line) { s_stringstream.str(std::string("")); s_stringstream << fname << '(' << line << ") : test> " << msg; dummy_puts( s_stringstream.str().c_str() ); } // strstream void test_strstream_local(const char* msg, const char* fname, unsigned line) { char buf[1024]; strstream ss(buf, 1024, std::ios::out); ss << fname << '(' << line << ") : test> " << msg << ends; dummy_puts( buf ); } static char s_strstream_buf[1024]; static strstream s_strstrem(s_strstream_buf, 1024, std::ios::out); // strstream void test_strstream_static(const char* msg, const char* fname, unsigned line) { s_strstrem.seekp(0, ios::beg); s_strstrem << fname << '(' << line << ") : test> " << msg << ends; dummy_puts( s_strstrem.str() ); } // 固定バッファのみのstream void test_chararystream_local(const char* msg, const char* fname, unsigned line) { CharAryStream<1024> ssb; ssb << fname << '(' << line << ") : test> " << msg; dummy_puts( ssb.c_str() ); } static CharAryStream<1024> s_charAryStream; // 固定バッファのみのstream void test_chararystream_static(const char* msg, const char* fname, unsigned line) { s_charAryStream.clear_buf(); s_charAryStream << fname << '(' << line << ") : test> " << msg; dummy_puts( s_charAryStream.c_str() ); } // =========================================================================== // 計測&チェック typedef void (*test_print_func_t)(const char* msg, const char* fname, unsigned line); double test(test_print_func_t test_print, int m, size_t size, unsigned flags, const char* ttl) { unsigned char verboss = flags & 1; if (verboss) { fprintf(stderr, "\t%s:start\n", ttl); dummy_puts_set_mode(verboss); //size = 1; #ifdef MALLOC_CHK my_malloc_count_init(); #endif } unsigned j; // ダミー表示=文字列処理時間 の計測. PerfCnt_tick_t start_time = PerfCnt_getTick(); // 計測開始 switch (m) { case 0: for (j = 0; j < size; ++j) test_print("dummy message\n", "a.c", 1); break; case 1: for (j = 0; j < size; ++j) test_print("dummy message\n", "abcdefghijklmnopqrstuvwxyz0123456789.tmp", 1234567890); break; } PerfCnt_tick_t elapsed = PerfCnt_getTick() - start_time; // 計測終了 double e = elapsed * 1.0 / (PerfCnt_tickPerSec() * size); if (verboss) { fprintf(stderr, "\t%s:end (%f)\n", ttl, e * 1000000.0); #ifdef MALLOC_CHK my_malloc_count_disp(); #endif } return e; // ソート時間. } void test_all(unsigned size, unsigned v) { const char* nm[32] = {0}; double elaped[32][3] = { {0} }; init_test_std_string_static(); fprintf(stderr, "\nダミーメッセージの文字列処理時間の計測\n" ); if (v) fprintf(stderr, "出力回数 %9d (の平均)\n", size); // 各ソートのチェック. for (unsigned i = 0; i < 2; ++i) { unsigned k = 0; nm[k] = "sprintf " ; elaped[k][i] = test(test_sprintf , i, size, v, nm[k]); ++k; nm[k] = "pointer+memcpy+strlen" ; elaped[k][i] = test(test_memcpy , i, size, v, nm[k]); ++k; nm[k] = "strcpy+strcat " ; elaped[k][i] = test(test_strcat , i, size, v, nm[k]); ++k; nm[k] = "std::string (+) " ; elaped[k][i] = test(test_std_string , i, size, v, nm[k]); ++k; nm[k] = "std::string (rsv +=) " ; elaped[k][i] = test(test_std_string_rsv , i, size, v, nm[k]); ++k; nm[k] = "std::string static " ; elaped[k][i] = test(test_std_string_static , i, size, v, nm[k]); ++k; #ifdef USE_WTL nm[k] = "WTL::CString (+) " ; elaped[k][i] = test(test_ms_cstring , i, size, v, nm[k]); ++k; nm[k] = "WTL::CString (rsv +=)" ; elaped[k][i] = test(test_ms_cstring_rsv , i, size, v, nm[k]); ++k; nm[k] = "WTL::CString Format " ; elaped[k][i] = test(test_ms_cstring_format , i, size, v, nm[k]); ++k; #endif nm[k] = "stringstream local " ; elaped[k][i] = test(test_stringstream_local , i, size, v, nm[k]); ++k; nm[k] = "stringstream static " ; elaped[k][i] = test(test_stringstream_static , i, size, v, nm[k]); ++k; nm[k] = "strstream local " ; elaped[k][i] = test(test_strstream_local , i, size, v, nm[k]); ++k; nm[k] = "strstream static " ; elaped[k][i] = test(test_strstream_static , i, size, v, nm[k]); ++k; nm[k] = "CharAryStream local " ; elaped[k][i] = test(test_chararystream_local , i, size, v, nm[k]); ++k; nm[k] = "CharAryStream static " ; elaped[k][i] = test(test_chararystream_static , i, size, v, nm[k]); ++k; } // 実行結果の出力 printf("\n*** ダミーメッセージの%d回の平均の文字列処理時間(μ秒)\n", size); printf("※数値→文字列の書式のない文字列操作ではltoaで数値を文字列化\n"); printf("\n"); for (unsigned j = 0; j < 32; ++j) { if (nm[j] == 0) continue; printf(",%-21s ", nm[j]); for (unsigned i = 0; i < 2; ++i) { double e = elaped[j][i]*1000000.0; if (e > 0) printf(",%12.3f", e); else printf(",%12s", "---"); } printf("\n"); } } int main(int argc, char* argv[]) { unsigned size = 1; unsigned v = 0; // オプションチェック for (int i = 1; i < argc; ++i) { if (strncmp(argv[i], "-c",2) == 0) { // ループ回数. size = strtol(argv[i]+2,0,0); if (size < 1) size = 1; } else if (strcmp(argv[i], "-v") == 0) { v = 1; } } test_all(size, v); return 0; }