LINUX.ORG.RU

Int в Hex, ускорить и укоротить

 ,


1

2

Можно ли заоптимизировать эту функцию?

char * intToHex(int32_t value, uint32_t up, uint32_t pre, uint32_t msize)
{
    const char * hexdigit[2] = {"0123456789abcdef",
                                "0123456789ABCDEF"};

    union itou
    {
        int32_t  i;
        uint32_t u;
    };

    union itou conv;
    conv.i = value;

    uint32_t pos = 0;
    char * result;
                                    /* 0x    FF FF FF FF         \0 */
    if (!(result = malloc(sign(pre) * 2 + sizeof(uint32_t) * 2 + 1)))
        return 0;

    if (pre)
    {
        strcpy(result, "0x");
        pos = 2;
    }

    while (1UL << (msize * 4) > conv.u)
    {
        result[pos++] = '0';
        msize--;
    }

    while (conv.u != 0)
    {
        result[pos++] = hexdigit[sign(up)][conv.u & 0xF];
        conv.u >>= 4;
    }

    result[pos] = '\0';

    return result;
}

★★

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

malloc резервирует виртуальную память, коей 2^48 на современных системах. реальная физическая память выделяется по обращению к странице

MyTrooName ★★★★★
()

Не угадал автора по топику.

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

The C PL

ANSI C K&R 2ed:

из Введения:

В языке нет каких-либо средств распределения памяти помимо возможности определения статических переменных и стекового механизма при выделении места для локальных переменных внутри функций. Нет в нём «кучи» и «сборщика мусора».

...

Всё это - механизмы высокого уровня, которые в Си обеспечиваются исключительно с помощью явно вызываемых функций.

K&R 1ed:

из Введения:

В языке не определяются никакие средства управления памятью, кроме статических определений и стековой дисциплины для локальных переменных функций; здесь нет механизмов типа «кучи» из Алгола 68 и его «сборщика мусора».

...

Эти механизмы высшего уровня должны обеспечиваться явно вызываемыми функциями.

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

А какой у тебя сейчас интернет? У меня мегафон, очень даже ок, если не скакать LTE-3G и обратно.

P.S. Сколько ты ещё будешь в нижнем?

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

по модели памяти

ничего всеобъемлющего не посоветую, но начать можно отсюда: http://ru.wikipedia.org/wiki/Страничная_память

как Си с ней работает

с виртуальной/физической памятью работает в первую очередь ядро. man mmap

malloc же обращается к ядерному mmap, предоставляя уже более простое API выделения памяти. как именно он работает - зависит от конкретной реализации.

рандомная статья из гугла: http://cs.mipt.ru/docs/comp/rus/os/common/bolshakov/node21.html

MyTrooName ★★★★★
()

поставить перед ее определнием inline?

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

Да я уже вчера свалил на ночном экспрессе в Москву. Сейчас уже в Ставрополе у родителей сижу.

У меня там был Билайн (просто в Ставрополе у билайна самые классные тарифы на 4G). А я даже не подозревал, что у этой заразе в НН нет 4G (при этом симки на 4G продают, сволочи!).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от mono

P.S. Ничего, еще, наверное, к осени приеду.

Мы теперь еще долго этот несчастный криостат будем туда-сюда возить...

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от sambist

Для потомков: поправил математику:

errors intToHex(char ** result, int32_t value, uint32_t up, uint32_t pre, uint32_t msize)
{
    if (!result)
       return ERR_BADPOINTER;

    if (msize > 8)
        msize = 8;

    const char * hexdigit[2] = {"0123456789abcdef",
                                "0123456789ABCDEF"};
    union itou
    {
        int32_t  i;
        uint32_t u;
    };

    union itou conv;
    conv.i = value;

    uint32_t pos   = 0;
    int32_t  upsgn = sign(up);
                                    /* 0x    FF FF FF FF         \0 */
    if (!(*result = malloc(sign(pre) * 2 + sizeof(uint32_t) * 2 + 1)))
        return ERR_BADALLOC;

    if (pre)
    {
        (*result)[0] = '0';
        (*result)[1] = 'x';
        pos = 2;
    }

    while (1UL << ((msize)) > (conv.u + 1))
    {
        (*result)[pos++] = '0';
        msize--;
    }

    uint32_t i = pos + floor(log10(conv.u) / log10(16));
    while (conv.u != 0)
    {
        (*result)[i--] = hexdigit[upsgn][conv.u & 0xF];
        conv.u >>= 4;
        pos++;
    }

    (*result)[pos] = '\0';

    return ERR_SUCCESS;
}

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

А если я захочу знаковое перевести? При приведении потеряется знак или будет опасность овервлова.

P.S. Быстрофикс:

---while (1UL << ((msize)) > (conv.u + 1))
+++while (1UL << ((msize)) > ((unsigned long long)conv.u + 1))

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

потому что такое:

obj = alloc_obj();
do_op (obj);
free_obj(obj);

более явно, чем

obj = alloc_and_do_obj();
free_obj(obj);
char * c = strdup(a);
free(a);

Такие дела, POSIX стандарт.

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

Аноним несет пургу: ENOMEM никогда не возникнет. Не бывает такого в линуксе. Разве что если ты oomkiller отключишь совсем.

Покажи, где это в мане написано. Покажи, где сказано, что OOM killer работает синхронно, а не дает NULL на время работы. Покажи, где забожились, что поведение не изменится со временем. Покажи, где в конце концов гарантировано !NULL прямо сейчас (да хоть в коде!).

Рассчитывать на такое - признак быдлокодера.

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

Ведро такое. Дырявое. Было б нормальное — да. А так — какое ведро говеное, такие и быдлокодеры.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от sambist

Измененная копипаста выше - выпилен анскилл и маллоки.

uint64_t intToHex2(uint32_t value, uint32_t up) {//формат 0x0001
  char * hexdigit = &"0123456789abcdef0123456789ABCDEF"[up ? 16 : 0];
  uint64_t ret = 0; char * ptr = &ret;

  switch(7) {
    case 7: ptr[7] = hexdigit[value & 0xf]; value >>= 4;
    case 6: ptr[6] = hexdigit[value & 0xf]; value >>= 4;
    case 5: ptr[5] = hexdigit[value & 0xf]; value >>= 4;
    case 4: ptr[4] = hexdigit[value & 0xf]; value >>= 4;
    case 3: ptr[3] = hexdigit[value & 0xf]; value >>= 4;
    case 2: ptr[2] = hexdigit[value & 0xf]; value >>= 4;
    case 1: ptr[1] = hexdigit[value & 0xf]; value >>= 4;
    case 0: ptr[0] = hexdigit[value];
  }
  return ret;
}

uint64_t intToHex(uint32_t value, uint32_t up) {//формат 0x1
  char * hexdigit = &"0123456789abcdef0123456789ABCDEF"[up ? 16 : 0];
  uint64_t ret = 0; char * ptr = &ret;

  switch(_bit_scan_reverse(value) >> 2) {
    case 7: ptr[7] = hexdigit[value & 0xf]; value >>= 4;
    case 6: ptr[6] = hexdigit[value & 0xf]; value >>= 4;
    case 5: ptr[5] = hexdigit[value & 0xf]; value >>= 4;
    case 4: ptr[4] = hexdigit[value & 0xf]; value >>= 4;
    case 3: ptr[3] = hexdigit[value & 0xf]; value >>= 4;
    case 2: ptr[2] = hexdigit[value & 0xf]; value >>= 4;
    case 1: ptr[1] = hexdigit[value & 0xf]; value >>= 4;
    case 0: ptr[0] = hexdigit[value];
  }
  return ret;
}
uint64_t itohs(uint32_t x) {
  __m64 mask_a = _mm_set_pi8(0, 0x0f, 0, 0x0f, 0, 0x0f, 0, 0x0f);
  __m64 mask_b = _mm_set_pi8(0x0f, 0, 0x0f, 0, 0x0f, 0, 0x0f, 0);
  __m64 v = _mm_set1_pi32(x);
  v = _mm_shuffle_pi8((__v8qi)v, (__v8qi)_mm_set_pi8(0, 0, 1, 1, 2, 2, 3, 3));
  __m64 a = _mm_and_si64(_mm_srl_pi32(v, _mm_set1_pi32(4)), mask_a), b = _mm_and_si64(v, mask_b);
  __m64 ab = _mm_or_si64(a, b);
  __m64 ret = _mm_add_pi8(_mm_add_pi8(_mm_and_si64(_mm_cmpgt_pi8(ab, _mm_set1_pi8(9)), _mm_set1_pi8('a' - '0' - 10)), _mm_set1_pi8('0')), ab);
  return (uint64_t)ret;
}

Быстрая байда(раза в 2быстрее первых 2-х) на ммх + ssse3(шафл). Может считать сразу 1(mmx - сейчас)-2(sse2)-4(avx2)числа.

Переводить в формат 0x - так:

typedef struct {
  char zx[2];
  uint64_t val __attribute__((packed));
  char null;
} zx_format_t;

int main(void) {
  fprintf(stderr, "%s\n", &(zx_format_t){{'0', 'x'}, intToHex(0x123, 1)});
  fprintf(stderr, "%s\n", &(zx_format_t){{'0', 'x'}, (intToHex2(0x12345678) & (-1ul >> (8 * 7)))});//так обрезать "старшие" байты.
}
anonymous
()
Ответ на: комментарий от anonymous
uint64_t itohs(uint32_t x) {
  __m64 mask_a = _mm_set_pi8(0, 0x0f, 0, 0x0f, 0, 0x0f, 0, 0x0f);
  __m64 mask_b = _mm_set_pi8(0x0f, 0, 0x0f, 0, 0x0f, 0, 0x0f, 0);
  __m64 v = _mm_set1_pi32(x);
  v = _mm_shuffle_pi8(v, _mm_set_pi8(0, 0, 1, 1, 2, 2, 3, 3));
  __m64 a = _mm_and_si64(_mm_srl_pi32(v, _mm_set1_pi32(4)), mask_a), b = _mm_and_si64(v, mask_b);
  __m64 ab = _mm_or_si64(a, b);
  __m64 ret = _mm_add_pi8(_mm_add_pi8(_mm_and_si64(_mm_cmpgt_pi8(ab, _mm_set1_pi8(9)), _mm_set1_pi8('a' - '0' - 10)), _mm_set1_pi8('0')), ab);
  return (uint64_t)ret;
}

Фикс, то не соберётся по дефолту.

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

вот если бы в вашей сишечке с ссе и интринсиками можно было так же незатратно писать, но чтобы из глаз кровь не лилась!

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

Я тебе уже показал, что возвращает NULL. Возможно при предыдущем запросе отдаёт меньше нужного, мне не хочется проверять ибо лиса уйдёт подумать на полчаса не смотря на возвращение памяти.

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

Либо memset() просто не заполняет всё запрошенное несуществующее пространство, что более вероятно.

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

Для илитного запила на векторной гнусишке нужно просто написать сетов и всё - юзай обычный си:

typedef char v16_t __attribute__((__vector_size__(16)));
typedef short v8_t __attribute__((__vector_size__(16)));
typedef int v4_t __attribute__((__vector_size__(16)));
typedef long long v2_t __attribute__((__vector_size__(16)));

v16_t v16_set1(int8_t x) {
  return (v16_t){x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, };
}
v8_t v8_set1(int16_t x) {
  return (v8_t){x, x, x, x, x, x, x, x};
}
v4_t v4_set1(int32_t x) {
  return (v4_t){x, x, x, x};
}
v2_t v2_set1(int64_t x) {
  return (v2_t){x, x};
}
v8_t v8_set(int16_t a, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g, int16_t h) {
  return (v8_t){a, b, c, d, e, f, g, h};
}
v4_t v4_set(int32_t a, int32_t b, int32_t c, int32_t d) {
  return (v4_t){a, b, c, d};
}
v2_t v2_set(int64_t a, int64_t b) {
  return (v2_t){a, b};
}


v16_t v16_shuffle(v16_t v, v16_t mask) {
  return __builtin_shuffle(v, mask);
}

uint64_t itohs_gnuvecc(uint32_t x) {
  v16_t mask_a = v8_set1(0x000f), mask_b = v8_set1(0x0f00);
  v16_t shuffle_mask = v2_set1(0x0000010102020303ul);
  v16_t v = v16_shuffle(v4_set1(x), shuffle_mask);
  v16_t a = (v16_t)((v4_t)v >> v4_set1(4)) & mask_a, b = v & mask_b, ab = a | b;
  v16_t ret = ab + ((ab > v16_set1(9)) & v16_set1('a' - '0' - 10)) + v16_set1('0');
  return ((v2_t)ret)[0];
}

Тут всё цивильно, кроме (v16_t)((v4_t)v >> v4_set1(4)) - это кастыль, ибо нету сдвигов для байтов. Всё будет работать, но гцц переделает это в другие сдвиги - для сдвига вправо похрена, а вот в лево. Поэтому, чтобы гцц не гинерил говно - такой кастыль.

Этот код будет работать везде, даже если у тебя вообще нет симдов, ссе и прочего говна. Правда будет тормазным говном(хотя на уровне примеров пацанов).

Ну и конечно надо понимать что такое вектора и как там они между собой хреначатся.

Тут есть ещё одна пробелма - касты векторов, с этим жопа, когда юзаешь интринсики и векторную сишку рядом - -flax-vector-conversions спасает.

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

Ещё раз.

Ну давай, я как-то тебя пропустил.

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

До, до. Вот какраз такие рукожопы ничего и не могут.

int main(int argc, char ** argv) {
  size_t sz = (1024 * 1024 * 1024) * 1lu;
  do {
    void * zz = malloc(sz);
    void * zz1 = malloc(sz);
    void * zz2 = malloc(sz);
    if(!zz || !zz1 || !zz2)
      if(ENOMEM == errno) {
        fprintf(stderr, "hello ENOMEM\n");
        perror("fail");
        //abort();
        _exit(EXIT_FAILURE);
      }
    memset(zz, 1, sz);
    memset(zz1, 1, sz);
    memset(zz2, 1, sz);
    malloc_stats();
  } while(1);
  getchar();//просто эпик.
  return 0;
}

Твоё говно работает только для одного юзкейса - взял(понадеялся, что никто другой память твою не забрал), сделал префаулт и только потом следующую аллокацию.

Не работает на аллокации меньше пейджсайза(95% вообще всех юзкейсов), не работает когда кто-то другой заберёт твою память, не работает при нескольких аллокациях подряд без префаулта.

И да:

для программиста на си непозволительное рукожопие считать иначе

Для программиста на си непозволительное рукожопие считать, что впихнув проверку на анал он что-то смог - это удел нулёвой обезьяны.

Твои фокусы с overcommit memory никому не интересны.

Какие-такие фокусы? Я тебе открою тайну, но оверкоммит - это кастыль созданный специально, чтобы проверка на нал работала. И какраз таки ты играешь с ним.

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

Я тебе уже показал, что возвращает NULL. Возможно при предыдущем запросе отдаёт меньше нужного, мне не хочется проверять ибо лиса уйдёт подумать на полчаса не смотря на возвращение памяти.

Можно расшифровать это проявление нулёвости в более вменяемый вид, чтобы я его понял?

Кто что отдаёт? И каком таком запросе. Почему твоё говно работает - из-за оверкоммита. Там юзается проверка, аля (alloc_len > total_free_realmem()) return 0;

Дак вот, твой префаулт уменьшает этот total_free_realmem(), а так же его уменьшает что угодно в системе.

И никто тебе не гарантирует, что total_free_realmem() во время вызова твоего маллока и во время мемсета будет одним и тем же. Дак вот подумай. Причем в дефолтном юзкейсе память заполняется куда медленнее, чем мемсетом.

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

меньше пейджсайза

ну ок, для линукса это так и на таких маленьких аллокациях нас ждёт фейл. Это как-то отменяет сказанное мной? Я люблю узнавать новое и исправлять/дополнять свои знания, но в твоём ответе я вижу 0 информации. http://www.etalabs.net/overcommit.html

и чем тебе не угодил getchar()? естественно, он там лишний, но это самый простой способ заставить не завершаться.

с практической точки зрения ты возможно и прав, но это относится к отложенной аллокации и не повод не проверять возвращаемое значение вовсе (а только при malloc < ~4096 байт, но мы же не этот случай обсуждаем, правда?) вероятность, что кто-то у нас отберёт наши последние несколько мегабайт памяти до того как ядро освободит нам больше при корректном подходе к аллокации довольно мала.

пропустил

нельзя упускать такую еду!

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

Эй, мразь с 5.2, к ноге. Ты же мне расскажешь почему ты меня за 5.2 забанил, а ублюдка за 5.2 нет? Хотя там было ещё более явно 5.2? Или ты меня забанил не за 5.2? А потамучто ты ублюдок?

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

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

Пруфцы где там я невнятно что-то выражаю, пруфцы где там я там забыл о чем говорил. О каких пруфцах ты кукарекал, и о каких таких «вещах» я говорю с умным видом.

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

У тебя каша какая-то в голове, серьёзно.

Хотябы пару примеров.

Твои высказывания крайне редко к месту.

Хотябы пару примеров.

Ты же понимаешь, что ты будешь нести любую херню, лижбы не вернутся к теме?

Ещё раз, ублюдок. Ты нахрена съезжаешь с темы? Я тебе не собрать по развитию, твой кукаретинг на меня не действует. Ты ничтожество, задача которого обсираться и валяться у меня в ногах в своём говне.

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

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

По поведению сразу видно ничтожную мразь со стандными повадками. Это настолько жалко и примитивно, когда ничтожество обсирается и делает вид, что оно не понимает о чем я говорю. Т.е. ничтожеству важно мнение публики, а не сам факт обсёра.

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

Почитай обсосков выше, почитай свои месаги. Хотя твой мозжечок не даст тебе принять свой обсёр - он даст тебе принять чужей обсёр. Вот почитай и погляди почему и на чем пацаны обосрались, попытайся выделить признаки обсёра. А потом поищи их у себя. Авось мозжечок не заблокирует твои 2-3извилины и ты возможно что-то поймёшь.

anonymous
()
16 августа 2014 г.
Ответ на: комментарий от Eddy_Em

Вот, кстати, царь правильно говорил, что нет смысла проверять результат malloc: он никогда не вернет NULL!

А потом и возникает:

«Я написал свою программу под $OS_NAME, запускаю под %OS_NAME%, а она не работает. Почему?»

А потому, что если написано в документации, что может вернуть NULL, значит нужно проверять и учитывать это.

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

запускаю под %OS_NAME%

Я уж точно не запускаю ☺

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Вот, кстати, царь правильно говорил, что нет смысла проверять результат malloc: он никогда не вернет NULL!

А в мане сказано иначе:

The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

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

зачем вызывать malloc с size=0

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