LINUX.ORG.RU

А вы уверены, что у вас производительность проседает именно на строках? На каких именно операциях? Сравнение? Конкатенация?

P.S. От себя советую использовать std::string, можно завернутый в MySuperString.h

typedef std::string MySuperString

trex6 ★★★★★
()
Последнее исправление: trex6 (всего исправлений: 1)

на char* очень удобно парсить текст, тут он предпочтительней и даст большой прирост скорости/экономии памяти, если же речь идет о простых динамических строках - без разницы, если хранить вместе с char* и размер строки+буфера, если не хранить - то на таких строках еще и проседание получить можно

wota ★★
()

ну и еще одно отличие - char[] можно положить на стек, std::string (его буфер) в теории тоже можно, но на практике я такого не видел

wota ★★
()
Последнее исправление: wota (всего исправлений: 1)
Ответ на: комментарий от wota

на char* очень удобно парсить текст

Особенно utf-8.

Tark ★★
()
Ответ на: комментарий от cvv

И как ты собираешься от этой проблемы избавиться путём перехода на char *? Память-то выделять всё равно придётся

Gvidon ★★★★
()
Ответ на: комментарий от aptyp

Что мешает то же самое сделать с std::string? Если зарезервированной памяти хватает, string никакой маллок дёргать не будет

Gvidon ★★★★
()
Ответ на: комментарий от Gvidon

Ничего, как оказалось. Предлагаю ТС пользоваться всё таки std::string::reserver

aptyp ★★★★
()
Ответ на: комментарий от cvv

Унаследовать std::string и переопределить append()?

Если пойдете по такому пути и все получится - отпишитесь где-нибудь, было бы очень интересно посмотреть на подобный опыт.

trex6 ★★★★★
()

Если strlen() хотпойнтом не является, то абсолютно фиолетово.

Но вообще имеет смысл использовать stl::string чисто из соображений удосбтва. А если работа с текстом является критичной к производительности, имеет смысл разработать собственную структуру данных, оптимизирвоанную под задачу. Например, если стоит задача быстр-быстро конкатенировать много строк, то возможно решением окажется завернуть всю работу в класс, который физически строки не конкатенирует, а строит вектор из чанков.

geekless ★★
()
Ответ на: комментарий от wota
    string SampleProcessor::ComputeGpioVal(unsigned int gpioVal)
    {  
        unsigned int i;
        string gpioStr;

        i = 1 << (sizeof(gpioVal) * 8 - 1);

        gpioStr = "";
        while (i > GPIO_MASK_LIMIT)
        {  
            if (gpioVal & i)
                gpioStr += "1";
            else
                gpioStr += "0";
            i >>= 1;
        }
        return gpioStr;
    }

частота вызова этой ф-и - около миллиона раз в секунду

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

От задачи же зависит. Так да, выделение памяти в куче это долгооо...

AIv ★★★★★
()
Ответ на: комментарий от cvv

1. статическими буферами

Ты и так можешь переопределить аллокатор, чтобы он использовал хоть файлы на удаленном ресурсе, но сильно ли именно статические буферы увеличат скорость? reserve() выделит заранее память в куче и не будет ничего выделять, пока хватит места.

note173 ★★★★★
()
Ответ на: комментарий от cvv

Если так заботит производительность, можно наваять свой стринг (или как то искорежить stl-ный) на общем кольцевом буфере. Если конечно известна оценка сверху для строки, она относительно невелика, код не параллельный и тд. Если код параллельный - под каждую нить нужен будет свой буфер. Быстрее сделать в принципе невозможно;-)

Ну и буфера в куче, при запуске выделяются, при завершении освобождаются.

AIv ★★★★★
()
Ответ на: комментарий от cvv

Если все упирается тока в эту ф-ю, то м.б. передавать результат не по значению а по ссылке? Сделаете один раз строку и будете ее юзать всю дорогу. Только надо посмотреть как оператор += в std::string реализован, ИМНО все же быстрее (и правильней) в данном слуае работать через gpioStr = '0'

AIv ★★★★★
()
Ответ на: комментарий от cvv

а с const char[] malloc'ать при конкатенации типа не нужно? std::string тоже можно, емнип, буфер с запасом выделять

marvin_yorke ★★★
()
Ответ на: комментарий от cvv

Тогда тем более сразу выделять под эту строчку, передавать результат по ссылке, если потоков нет.

aptyp ★★★★
()
Ответ на: комментарий от cvv

ты упоролся. зачем тебе здесь строки? битовые маски отменили? или хотя бы задай начальный размер строки равным GPIO_MASK_LIMIT. Я так понял, у тебя эмулятор микроконтроллера какого-то, значит памятью можно пожертвовать ради производительности, тем более что GPIO регистров явно немного и они небольшие

marvin_yorke ★★★
()
Ответ на: комментарий от cvv

а, я понял, ты в текстовую форму переводишь значение регистра. Ну тогда тем более с запасом выделяй и все. Размер регистра известен же заранее

marvin_yorke ★★★
()
Ответ на: комментарий от cvv
gpioStr = "";

лишнее

gpioStr += "1";

быстрее сделать gpioStr.push_back( '1' ), ну и в данном случае очевидно быстрее всего будет сохранять результат в char[] на стеке, который будет передан параметром в функцию

wota ★★
()
Ответ на: комментарий от AIv

Можно использовать одну строку.

Но вообще в этой ситуации действительно std::string не нужен.

note173 ★★★★★
()
Последнее исправление: note173 (всего исправлений: 1)
Ответ на: комментарий от AIv

Переделал на:

    void SampleProcessor::ComputeGpioVal(unsigned int gpioVal, string& gpioStr)          
    {  
        unsigned int i;

        i = 1 << (sizeof(gpioVal) * 8 - 1);

        gpioStr.clear();
        gpioStr.reserve(5);
        while (i > GPIO_MASK_LIMIT)
        {  
            if (gpioVal & i)
                gpioStr += "1";
            else
                gpioStr += "0";
            i >>= 1;
        }
    }

получил уменьшение общего времени выполнения этой ф-и с 35% до 21%. А также malloc() улетел вниз по количеству вызовов и соответсвенно потреблению ресурсов.

cvv ★★★★★
() автор топика
Последнее исправление: cvv (всего исправлений: 1)

Ты сравниваешь разные штуки в плане интерфейса. char * - это не строки, а массив символов, который по соглашению имеют \0 для обозначения конца «строки». Все остальное - как сделаешь. std::string полноценный тип для представления строк, с соответствующими операциями. С char * все будет зависеть от тебя, но если у тебя не простая последовательная обработка текста, а «классическая» работа со строками, то вряд ли у тебя получится что-либо сильно быстрее std::string.

anonymous
()
Ответ на: комментарий от cvv

sizeof(gpioVal) тождентсвенно ровна sizeof(unsigned int)

что-то у тебя не так, если функция не зависит от значения gpioVal или?

дальнейшие попытки оптимизировать предпринимать не уяснив этот момент сложно, потому что в случае если тебе нужен sizeof(unsigned int) у будет тебя фиксированный массив 32 байта и тебе собсна string может быть и не нужен.

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от wota

по моим измерениям push_back() более медленный чем operator+=(). замена += на push_back увеличила время выполнения ф-и с 21% до 26%.

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

значит это косяк в конкретной реализации std::string, кстати std::string из libstdc++ еще и имеет подсчет ссылок, что полный абзац

wota ★★
()
Ответ на: комментарий от cvv

Зачем тебе здесь класс строки вообще в цикле? Выделяй chat s[sizeof(чего-то там) + 1] на стеке и пиши в него при помощи s[j] = (какое-то условие) ? '1' : '0';

А потом засовывай результат в строку.

geekless ★★
()
Ответ на: комментарий от cvv

кстати там точно было различие только в push_back? я проверил - у меня наоборот, с g++ 4.7.2 push_back процентов на 15 быстрее

wota ★★
()
Ответ на: комментарий от cvv

Смотрю ещё раз и до меня доходит что ты делаешь что-то совершенно ненужное.
Эту функцию надо разделить на две:
1) отрубает у твоего числа log(GPIO_MASK_LIMIT) бит
2) общая функция преобразующая число в строку(а лучше массив символов) содержащую двоичное число.

invy ★★★★★
()
Ответ на: комментарий от geekless

спасибо - то что нужно.

cvv ★★★★★
() автор топика
Ответ на: комментарий от wota

Это у меня была ошибка измерений. push_back действительно быстрее.

cvv ★★★★★
() автор топика
Ответ на: комментарий от cvv

подрихтуйте под свою архитектуру и пользуйтесь :)

#include <stdio.h>
#include <stdint.h>

uint64_t i2btab[257];

void init_i2btab() {
	int c;
	for(c=0;c<256;c++) {
		sprintf((char *)(i2btab+c),"%1d%1d%1d%1d%1d%1d%1d%1d",
			(c>>7) & 1,
			(c>>6) & 1,
			(c>>5) & 1,
			(c>>4) & 1,
			(c>>3) & 1,
			(c>>2) & 1,
			(c>>1) & 1,
			(c & 1));
	}
}

inline void uint64_bin_asciiz(uint64_t x,char *s) {
	0[(uint64_t *)s]=i2btab[(x>>(7*8))&0xff];
	1[(uint64_t *)s]=i2btab[(x>>(6*8))&0xff];
	2[(uint64_t *)s]=i2btab[(x>>(5*8))&0xff];
	3[(uint64_t *)s]=i2btab[(x>>(4*8))&0xff];
	4[(uint64_t *)s]=i2btab[(x>>(3*8))&0xff];
	5[(uint64_t *)s]=i2btab[(x>>(2*8))&0xff];
	6[(uint64_t *)s]=i2btab[(x>>(  8))&0xff];
	7[(uint64_t *)s]=i2btab[ x     &0xff];
	s[64]=0;
}

int main() {
	char bin[65];
	uint64_t c;
	init_i2btab();
	for(c=0;c<1000*1000*1000;c++) {
		uint64_bin_asciiz(c,bin);
	}
	return 0;
}
$ time ./a.out 
real	0m28.037s
user	0m28.034s
sys	0m0.000s
28 сек на млрд итераций цикла - нормально. Используя asm можно подсократить раза в 2 если не в 3 (там всего-то табличные подстановки).

для удобства в std:string вы всегда успеете обернуть результат, но когда не будет жесткого RT

MKuznetsov ★★★★★
()
Ответ на: комментарий от nanoolinux

А ты хотел, что бы я тебе запостил сюда operator +=() написаный на С?

я хотел увидеть подтверждение, что «char быстрее»

wota ★★
()
Ответ на: комментарий от wota

я хотел увидеть подтверждение

Чувак, const char даёт тебе возможность рулить памятью в ручную, на уровне указателей. Благодаря этому у тебя намного больше места для манёвров, чем для спп строк даже со своим кастомным аллокатором. Так что когда строки - узкое место в производительности у тебя нет другого выбора кроме как перейти на const char и пытаться замутить какой-то хитрый алгоритм который в одном случае (из которого проблемы) работает быстрее, а во всех остальных - медленее.

А то, что ты просил в посте выше похоже на

запили мне такое на с++
python -m SimpleHTTPServer
и естественно вариант на с++ ты не получишь, но это не будет означать, что питон быстрее чем с++.

Если ты понял о чём я.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Чувак, const char даёт тебе возможность рулить памятью в ручную, на уровне указателей

ты хотел сказать char*, а постоянно пишешь const char, ну да ладно

А то, что ты просил в посте выше похоже на

вообще не то, для сишных строк есть готовые функции:

http://www.cplusplus.com/reference/cstring/

тебе никто не запрещает их использовать вместе с realloc, чтоб получить тот же результат

и естественно вариант на с++ ты не получишь

на голом - нет, а вот ты с char* - можешь, потому пример вообще ни о чем

wota ★★
()
Ответ на: комментарий от nanoolinux

Дальше не читал. Пока.

наркоманы ITT пугаются и прячутся, когда им указывают, что в const char строку не поместишь (ну разве только пустую), окай - убегай дальше от реальности

wota ★★
()

с точки зрения ресурсоемкости нужно писать на С. потом наступит переломный момент и ты перестанешь надрачивать на мнимые оптимизации в виде c-style строк, избегания алгоритмов из stl и коллекций оттуда же.

x0r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.