1. Си / Говнокод #20086

    −51

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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, 27 Мая 2016

    Комментарии (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; }
      Ответить
      • Проверял на всякий случай, нет ли расхождений
        Ответить
    • Это все сраные говнонультерминированные Си-строки http://russian.joelonsoftware.com/Articles/BacktoBasics.html
      То ли дело пацкалестроки
      Ответить
      • Спольски сказочный пиздаблл
        Ответить
        • Да, он такой сказочный пиздабол, что уже культовый до мозга костей. И его статьи давностью 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 не читал, но осуждаю.
              Ответить
              • Да ты и статью не читал,ивидимо. Он даже пишет i am hungarian, и приводит говнопример с rwHeight
                Ответить
                • Всё я читал, правда в русском переводе. Не в этом, но тут смысл тоже сохранён: http://local.joelonsoftware.com/wiki/Как_заставить_неправильный_код_выглядеть _неправильно
                  Ответить
                  • Человек который пишет на vbs ведь педорас по определению, нет?
                    Ответить
            • > Например в статье "как микрософт проиграла битву за 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()` которая формат + ... передает вместо строки.
      Ответить
      • SnprintfBuilder
        Ответить
      • Оптимально, имхо, указатель на терминатор возвращать, а не бесполезное начало строки, как в 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.
        Ответить

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