Няшная / Говнокод #20086 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
xash_force_inline size_t Q_strncat( char *dst, const char *src, size_t size )
{
	register const char	*pchr;
	register const unsigned int *plongword;
	register unsigned int *pdst;
	register unsigned int len;

	const unsigned int himagic = 0x80808080, lomagic = 0x01010101;

	if( !dst || !src || !size )
		return 0;

	len = Q_strlen( dst );
	dst += len;
		

	if( ( unsigned long int )src & ( sizeof( int ) - 1) != ( unsigned long int )dst & ( sizeof( int ) - 1) )
		return len + Q_strncpy_unaligned( dst, src, size - len );

	// first, copy all unaligned bytes
	for( pchr = src; ( ( unsigned long int )pchr & ( sizeof( int ) - 1) ) != 0; pchr++, len++, dst++ )
	{
		*dst = *pchr;
		if( len >= size )
		{
			*dst = '\0';
			return len;
		}
		
		if( *pchr == '\0' )
			return len;
	}

	plongword = ( const unsigned int * ) pchr;
	pdst = ( unsigned int * ) dst;

	// plongword is aligned now, copy by 4 bytes
	while( true )
	{
		register unsigned int longword = *plongword++;

		// if magic check failed
		if( ( ( longword - lomagic ) & himagic ) != 0 || (size - len < 4) )
		{
			const char *pchar = ( const char * )( plongword - 1 );
			char *pchdst = ( char * )( pdst );
			int i;


			for( i = 0; i < 4; i++ )
			{
				pchdst[i] = pchar[i];

				if( len + i >= size )
				{
					pchdst[i] = '\0';
					return len + i;
				}
				if( pchar[i] == 0 )
					return len + i;
			}
		}

		len += sizeof( longword );
		*pdst++ = longword;
	}
	return 0;
}

/*
 * sanity checker
xash_force_inline size_t Q_strncat( char *dst, const char *src, size_t size )
{
	char buf1[100000], buf2[100000], r1, r2;
	if( !dst || !src || !size )
		return 0;
	if( size > 99999 )
		size = 99999;
	strncpy( buf1, dst, size );
	strncpy( buf2, dst, size );
	buf1[99999] = buf2[99999] = 0;

	r1 = Q_strncat_( buf1, src, size );
	r2 = Q_strncat2( buf2, src, size );
	if( r1 != r2 )
		printf("DIFFERENT RESULT %d %d %d %d %s\n%s\n", r1, r2, aligned, counter, buf1, src);
	if( strcmp( buf1, buf2 ) )
	{
		printf("DIFFERENT DATA %s %d %d %d %4s\n", src, size, aligned, counter, last);
		printf("1: %s\n", buf1);
		printf("2: %s\n", buf2);
		
	}
	//strncpy( dst, buf1, size );
	return Q_strncat2(dst, src, size);
	
}
*/

Оптимизация удалась, однако при виде этого кода становится не по себе. Что можно с этим сделать?

Запостил: mittorn mittorn, (Updated )

Комментарии (44) RSS

  • То есть как это.
    (0x10203040 - 0x01010101) & 0x80808080 == 0 // magic
    (0x10001C1C - 0x01010101) & 0x80808080 == 0x0EFF1B1B // no magic, '\0'
    (0xE0EFEEE6 - 0x01010101) & 0x80808080 == 0xDFEEEDE5 // no magic?
    Оптимизируются только строки в ASCII?
    Ответить
    • Ложные срабатывания лишь чуть понизят производительность. А не ascii строк там мало. Главное чтобы не пропустил 0.
      Такая провкрка заюзана в strlen в android и в glibc.
      Я предположил, что она действительно работает
      Ответить
  • /*
     *sanity checker
    xash_force_inline size_t Q_strncat( char *dst, const char *src, size_t size ) { return false; }
    Ответить
      • Да, он такой сказочный пиздабол, что уже культовый до мозга костей. И его статьи давностью 15 лет не теряют актуальности. А что сделал ты, guesto?

        А по делу, где-то terminatedzero катит, где-то паскалеизвращение, где-то верёвки... Все способы мудацкие, но серебрянной пули нет )
        Ответить
        • Редко кто обосрался столько раз, сколько это сделал Спольски.

          Например в статье "как микрософт проиграла битву за API" он наделал кучу предсказаний, и ни одно не сбылось. Чего стоит только высер про нет:

          В статье "Making Wrong Code Look Wrong" он предлагает использовать венгерскую нотацию зачем-то сокращая слова. Тоесть вместо "rowSize" называть переменную "rwSize" да еще и пишет на vbs. А еще пишет про какого-то Raymond Chen который "the best programmer in the world". Что бля? Что он сделал кроме книжки про "old new thing"?
          Ответить
          • Ну если ничего не писать, то не обосрёшься с предсказаниями, я гарантирую это. Я также гарантирую то, что чем больше ты предсказываешь, тем больше ты ошибёшься.
            В статье "Making Wrong Code Look Wrong" он ни хуя не предлагает использовать венгерскую нотацию. Даже скорее наоборот. Там он раскрыл хорошую тему некорректного применения этой самой нотации и привёл примеры, как это должно работать.
            Raymond Chen не читал, но осуждаю.
            Ответить
          • > Например в статье "как микрософт проиграла битву за API" он наделал кучу предсказаний, и ни одно не сбылось.
            Ну да, вон они уже убунту в свою винду встраивают официально, с поддержкой нативных системных вызовов
            Ответить
            • WSL делается чтобы не потерять рынок питонистов, рубистов и джснодовцев, которым под виндой не сладко. Это только для девелоперов, и кстати работает хуево, ибо бета
              Ответить
    • > Этот код базируется на алгоритме маляра Шлемиэля.

      При беглом прочтении показалось, что маляра звали Шамилем.
      Ответить
  • > Что можно с этим сделать?

    повесится.

    если у тебя `strcat()` является ботллнеком, то ты что-то капитально неправильно делаешь.

    я уже 5+ лет заменяю стандартный ебанутый strncat() на нечто типа:
    char* strncat2( char *dst, const char *src, size_t size )
    {
         size_t dl = strlen(dst);
         snprintf( dst+dl, size-dl, "%s", src );
         return dst;
    }

    но чаще я пользуюсь самописной `strncatfmt()` которая формат + ... передает вместо строки.
    Ответить
    • Оптимально, имхо, указатель на терминатор возвращать, а не бесполезное начало строки, как в strcat'ах...
      Ответить
      • З.Ы. Я вообще в одном сишном проекте сорвался и сделал нормальные строки с size и capacity...
        Ответить
        • Ура! Теперь в мире есть 654 реализации строк для сей.
          Ответить
        • > Оптимально, имхо, указатель на терминатор возвращать, а не бесполезное начало строки, как в strcat'ах...

          по моему личному опыту, возврат strcat()'а никому не нужен.

          strcat() и даже strncat() - это неэффективное убогое говно, и те кто ими пользуются/в тах местах где ими пользуются, "эффективность" просто и рядом не стояла. почему и на возврат всем посрать.

          и chained strcat()ы это все равно говно - по сравнению с одним snprintf()'ом.

          > З.Ы. Я вообще в одном сишном проекте сорвался и сделал нормальные строки с size и capacity...

          аналогично. но в 80% случаев, мудачество с strcat() просто заменяется одним snprintf()'ом.
          Ответить
    • Там уже используется Q_strncat везде и у меня нет в планах переписывать весь зависящий от него код
      Ответить
      • переписывать не надо - но вменяемые альтернативы добавить всегда имеет смысл.
        Ответить
    • Надо такой strcat делать, чтоб ему передавать сразу кучу указателей на строки через va_arg хрень, и он все их сшивал бы в одну, и чтоб еще многопоточно (или вообще через CUDA)
      Ответить
      • > кучу указателей на строки через va_arg хрень, и он все их сшивал бы в одну
        snprintf?

        > многопоточно
        У тебя строки такой длины, что это даст плюс и код не погрязнет в синхронизациях?
        Ответить
        • ну надо прикнуть. Если использовать не просто нуль терминированные строки, но еще и хранить длину самой строки(чтобы эту длину легко получить можно было) и надо к примеру сшить 10000 строк, средняя длина каждой допустим будет 1000 байт, то я думаю что если создать по треду на ядро и разбросать между ними равномерно все эти задания на впихивания всех этих строк в одну большую... А где собственно возникнут проблемы с синхронизацией? Ну будет у нескольких тредов некая общая память, в которую они набрасывают кучу других строк, как только одна нить закончила свое дело, она тупо перед смертью атомарно уменьшает какую-то переменную в общей для всех тредов памяти(а число там изначально выставлено такое, сколько тредов было создано), ну и так пока все треды не закончат свое дело и там не будет 0, после чего можно продолжать нормальное исполнение программы. Хотя можно тупо упереться в пропускную способность шины памяти, и вся эта возня окажется напрасной
          Ответить
          • > проблемы с синхронизацией
            Ну во-первых когда запускаешь треды и когда ждёшь их завершения. Во-вторых - на том же интеле из-за когерентности кеша очень плохо работает запись в общую память (кеши ядер отбирают друг у друга владение кешлайном).
            Ответить
            • Кешлайнов много, знаешь что тауое 8 way cache?

              Другой вопрос что можно сделать фолс шаринг случайно

              Для того и есть intel vtune
              Ответить
              • > фолс шаринг
                О нём и речь. Ну хотя х.з., границы строк довольно редко, потоков мало. Не должно сильно напрягать.
                Ответить
          • Если я правильно помню слова Царя - шину вполне можно забить одним потоком, если sse'шными командами лить.
            Ответить
          • > Ну будет у нескольких тредов некая общая память, в которую они набрасывают кучу других строк

            ага, вот только тебе надо сразу знать сколько каждый тред обработает, чтоб разделить эту память так, чтоб в нее можно было писать параллельно без установки ей единственного владельца
            то бишь тебе сначала придется посчитать длину строк и как то раскидать их по тредам
            Ответить
            • > посчитать длину строк
              >> Если использовать не просто нуль терминированные строки, но еще и хранить длину самой строки
              Ответить
              • общую длину участка памяти в который будет производить запись конкретный тред

                правда если они все фиксированной длины - будет попроще, но тогда получается какая то через чур надуманная задача
                Ответить
  • > ( unsigned long int )src
    uintptr_t же. А то на всяких вендах long слишком короткий...
    Ответить
  • Байтоёбства много, толку мало. Цари Нормальные пацаны такие вещи пишут на асмовставках. А лучше - вообще целиком на асме, а то мало ли, какие там неэффективные пролог и эпилог конпелятор сгенерирует.
    Ответить
    • Толк однако есть. И мне под arm надо, я не осилил его асм. + оно расчитано на то, что gcc может заюзать neon.
      Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8