Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > форматированный ввод-вывод. производительность.


Автор: boostcoder 2.6.2011, 12:08
всем привет.

следующий код:
Код

#include <iostream>
#include <sstream>
#include <cstdio>
#include <stdint.h>
#include <sys/time.h>
#include <string.h>

static const size_t iterations = 1024*100;
static const size_t item_val = 33;
static const size_t item_len = 3; // 0x33,0x33,0x20
static const size_t buf_size = iterations*item_len;
static char buf[buf_size];

inline uint64_t current_time() {
   struct timeval tv;
   gettimeofday(&tv, 0);
   return (tv.tv_sec*1000)+(tv.tv_usec/1000);
}

/***************************************************************************/

uint64_t binary_test() {
   uint64_t start = current_time();
   for ( size_t idx = 0; idx < iterations; ++idx ) {
      memcpy(&buf[idx*item_len], &item_val, item_len);
   }
   return current_time()-start;
}

/***************************************************************************/

uint64_t sprintf_test() {
   uint64_t start = current_time();
   for ( size_t idx = 0; idx < iterations; ++idx ) {
      sprintf(&buf[idx*item_len], "%02d ", item_val);
   }
   return current_time()-start;
}

/***************************************************************************/

uint64_t sscanf_test() {
   uint64_t start = current_time();
   size_t tmp;
   for ( size_t idx = 0; idx < iterations; ++idx ) {
      sscanf(&buf[idx*item_len], "%02d ", &tmp);
   }
   return current_time()-start;
}

/***************************************************************************/

uint64_t ostringstream_test() {
   uint64_t start = current_time();
   std::ostringstream os;
   os.rdbuf()->pubsetbuf(buf, buf_size);
   
   for ( size_t idx = 0; idx < iterations; ++idx ) {
      os << item_val << ' ';
   }
   return current_time()-start;
}

/***************************************************************************/

uint64_t istringstream_test() {
   uint64_t start = current_time();
   std::istringstream is;
   is.rdbuf()->pubsetbuf(buf, buf_size);
   size_t tmp;
   char space;
   for ( size_t idx = 0; idx < iterations; ++idx ) {
      is >> tmp >> space;
   }
   return current_time()-start;
}

/***************************************************************************/

int main() {
   std::cout << "binary_test()       : " << binary_test() << std::endl;
   std::cout << "sprintf_test()      : " << sprintf_test() << std::endl;
   std::cout << "sscanf_test()       : " << sscanf_test() << std::endl;
   std::cout << "ostringstream_test(): " << ostringstream_test() << std::endl;
   std::cout << "istringstream_test(): " << istringstream_test() << std::endl;
}

/***************************************************************************/

http://liveworkspace.org/code/1d747c7e7fe2a95423c646bfe48cde66

выдает такие результаты:
Цитата

binary_test()       : 13
sprintf_test()      : 18
sscanf_test()       : 4779
ostringstream_test(): 9
istringstream_test(): 16

время в миллисекундах.

любопытны три момента:
1. почему sscanf() работает так долго?
2. почему ostringstream работает быстрее чем sprintf() ?
3. может кто-то встречал реализацию форматировщиков ввода-вывода, работающую быстрее протестированных?

спасибо.

Автор: mes 2.6.2011, 12:20
Цитата(boostcoder @  2.6.2011,  11:08 Найти цитируемый пост)
ostringstream работает быстрее чем sprintf() 

хм.. а не кажется ли, что сравнение изначально нечестное ?

Автор: boostcoder 2.6.2011, 12:32
Цитата(mes @  2.6.2011,  12:20 Найти цитируемый пост)
а не кажется ли, что сравнение изначально нечестное ?

в смысле, что stream`ам приходится выполнять по две операции?
или что?

Автор: mes 2.6.2011, 12:34
в том смысле что принтфы надо мерять хотя бы с тем же boost.format, а не с ними _голыми_. 

Автор: boostcoder 2.6.2011, 12:37
mes, мне нужно форматировать ввод-вывод. потому я выбрал два варианта: 1) sprintf/sscanf, 2) ostringstream/istringstream.
кандидатуру boost.format не рассматривал.

Автор: mes 2.6.2011, 12:41
надо отличать форматированный вывод, от форматированного по шаблону... у первого естесственно будет выйгрыш в скорости.. 

Автор: Alca 2.6.2011, 12:43
Это релизная сборка или дебажная?

Автор: boostcoder 2.6.2011, 12:45
mes, значит мне нужен форматированный.

Alca, gcc -O2 main.cpp -omain

Автор: mes 2.6.2011, 12:49
глянул результаты  :
Цитата(boostcoder @  2.6.2011,  11:08 Найти цитируемый пост)
sscanf_test()       : 679550


scanf действительно меденнее, чем должен был быть по идеи..

Автор: Alca 2.6.2011, 13:09
http://codepad.org/kvs8ZG4Q
Код

sscanf(&buf[idx*item_len], "%02d ", &tmp);


маленький фикс:  smile 
Код

sscanf(&buf[idx*item_len], "%02zu ", &tmp);


Добавлено через 1 минуту и 49 секунд
http://codepad.org/4lZe5qee
Цитата

cc1plus: warnings being treated as errors
In function 'clock_t sscanf_test()':
Line 51: warning: ISO C++ does not support the 'z' scanf length modifier

 smile

Добавлено через 5 минут и 48 секунд
Цитата

Alca, gcc -O2 main.cpp -omain

а если с -03?

Автор: boostcoder 2.6.2011, 14:53
Цитата(mes @  2.6.2011,  12:49 Найти цитируемый пост)
scanf действительно меденнее, чем должен был быть по идеи

вот и я о том же!

Цитата(Alca @  2.6.2011,  13:09 Найти цитируемый пост)
"%02zu "

это не существенно.

Цитата(Alca @  2.6.2011,  13:09 Найти цитируемый пост)
а если с -03?


с О2:
Цитата

binary_test()       : 8
sprintf_test()      : 232
sscanf_test()       : 678191
ostringstream_test(): 161
istringstream_test(): 163

с О3:
Цитата

binary_test()       : 8
sprintf_test()      : 224
sscanf_test()       : 685044
ostringstream_test(): 166
istringstream_test(): 161


т.е. разницы почти никакой.

Автор: Alca 2.6.2011, 15:57
Цитата

может кто-то встречал реализацию форматировщиков ввода-вывода, работающую быстрее протестированных?

http://gitorious.org/kirelagin_asm/sprintf/blobs/master/sprintf.asm

Автор: boostcoder 2.6.2011, 16:01
хм.. smile 
жаль на асме...

Автор: Alca 2.6.2011, 16:03
Мне попадались как-то, но не помню по каким ключевым словам гуглил

Автор: boostcoder 2.6.2011, 17:37
похоже, придется stream`ы юзать.

всем спасибо.

Автор: volatile 3.6.2011, 00:41
Жаль что время измерено в секундах, а не в тиках процессора. (нельзя сравнить результаты на разных машинах, так как зависит от скорости процессора).

если интересно под виндой, студия 2008, машина довольно слабенькая (2007год) Intel 2160 1.8Ghz
результаты в милисекундах
Код

binary_test()       : 0
sprintf_test()      : 24
sscanf_test()       : 5128
ostringstream_test(): 132
istringstream_test(): 25


тоже самое в микросекундах, так как binary_test вообще не видно.
Код

binary_test()       : 431
sprintf_test()      : 24693
sscanf_test()       : 5128608
ostringstream_test(): 133220
istringstream_test(): 25657



Автор: boostcoder 3.6.2011, 08:28
Цитата(volatile @  3.6.2011,  00:41 Найти цитируемый пост)
а не в тиках процессора

а как такое сделать в линуксе?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)