logging with iostream/stdio/mmap
iostream/stdio とあと mmap を使って 簡易logging のベンチマークとか。
結果
- iostream
- 1.76625 usec
- stdio
- 1.24158 usec
- mmap
- 0.987958 usec
logging の呼び出し1回あたりの計算時間がこんな感じ。環境は Intel Core2 Duo 2.0GHz + gcc 4.0.1 on MacBook
しかし、iostream が結構遅いな。
#include <iostream> #include <unistd.h> #include <sys/time.h> static const size_t NUM_ITERATE = 500000; static const char* MESSAGE = "statement for logging performance " "test scenario"; extern void logging(const char* message); extern void init(void); extern void destroy(void); int main() { struct timeval start, end; unsigned long long elapsed; init(); gettimeofday(&start, NULL); for (size_t i = 0; i < NUM_ITERATE; i++) { logging(MESSAGE); } gettimeofday(&end, NULL); destroy(); elapsed = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); std::cout << static_cast<double>(elapsed) / NUM_ITERATE << std::endl; }
#include <fstream> #include <iomanip> #include <cassert> #include <unistd.h> #include <sys/time.h> #include <climits> static const char* LOG_DIR = "log/iostream"; static const size_t LIMIT = 1024 * 1024; static const size_t SIZE_OF_HEADER = 20; static int log_no = 0; static int pos; static std::ofstream out; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static void open_log() { if (out.is_open()) { out.close(); } log_no++; char filename[PATH_MAX]; sprintf(filename, "%s/%02d", LOG_DIR, log_no); out.open(filename); if (!out) { perror("std::ofstream::open"); exit(EXIT_FAILURE); } pos = 0; } void init() { pos = 0; } void destroy() { if (out.is_open()) { out.close(); } } void logging(const char* message) { int st; struct timeval tv; size_t len = strlen(message); st = gettimeofday(&tv, NULL); assert(st == 0); pthread_mutex_lock(&mutex); if (pos + len + SIZE_OF_HEADER + 1 > LIMIT || !out.is_open()) { open_log(); } out << std::setw(10) << tv.tv_sec << '.' << std::setw(6) << std::setfill('0') << tv.tv_usec << " : " << message << '\n'; pos += SIZE_OF_HEADER + len + 1; pthread_mutex_unlock(&mutex); }
#include <cstdio> #include <cstdlib> #include <cassert> #include <climits> #include <cstring> #include <unistd.h> #include <sys/time.h> #include <pthread.h> static const char* LOG_DIR = "log/stdio"; static const size_t SIZE_OF_HEADER = 20; static const size_t LIMIT = 1024 * 1024; static int log_no; static FILE* fp; static int pos; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static void open_log() { if (fp != NULL) { fclose(fp); } log_no++; char filename[PATH_MAX]; sprintf(filename, "%s/%02d", LOG_DIR, log_no); fp = fopen(filename, "w"); if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } pos = 0; } void init() { log_no = 0; fp = NULL; } void destroy() { if (fp != NULL) { fclose(fp); } } void logging(const char* message) { size_t len = strlen(message); size_t n; struct timeval tv; int st; pthread_mutex_lock(&mutex); if (pos + len + SIZE_OF_HEADER + 1 > LIMIT || fp == NULL) { open_log(); } st = gettimeofday(&tv, NULL); assert(st == 0); n = fprintf(fp, "%ld.%06ld : %s\n", tv.tv_sec, tv.tv_usec, message); pos += n; pthread_mutex_unlock(&mutex); }
#include <stdio.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <sys/time.h> #include <cassert> #include <cstring> #include <climits> #include <pthread.h> static int fd; static char *buffer; static size_t pos; static int log_no; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static const char* LOG_DIR = "log/mmap"; static const size_t LIMIT = 1024 * 1024; static const size_t SIZE_OF_HEADER = 20; static void open_log() { char filename[PATH_MAX]; int st; log_no++; if (fd >= 0) { munmap(buffer, LIMIT); ftruncate(fd, pos); close(fd); } sprintf(filename, "%s/%02d", LOG_DIR, log_no); fd = open(filename, O_RDWR | O_CREAT, 0600); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } st = ftruncate(fd, LIMIT); if (st == -1) { perror("ftruncate"); exit(EXIT_FAILURE); } buffer = reinterpret_cast<char *>(mmap(NULL, LIMIT, PROT_WRITE, MAP_SHARED, fd, 0)); if (buffer == reinterpret_cast<char *>(-1)) { perror("mmap"); exit(EXIT_FAILURE); } pos = 0; } void init() { fd = -1; log_no = 0; } void destroy() { if (fd >= 0) { munmap(buffer, LIMIT); ftruncate(fd, pos); close(fd); } } void logging(const char* message) { size_t len = strlen(message); size_t n = 0; struct timeval tv; gettimeofday(&tv, NULL); pthread_mutex_lock(&mutex); if (pos + len + SIZE_OF_HEADER + 1 > LIMIT || log_no == 0) { open_log(); } n = sprintf(buffer + pos, "%10d.%06d : %s\n", tv.tv_sec, tv.tv_usec, message); pos += n; pthread_mutex_unlock(&mutex); }