Я уже публиковал несколько модификаций для некоторых функций из libc, оптимизированных для быстрой работы на современных процессорах (см. категорию Algorithms and Technologies).
Все эти функции были реализованы в поисковом движке DataparkSearch Engine. Поскольку производительность этих функций, особенно в сравнении со стандартной реализацией на конкретной платформе, зависит от используемых микропроцессора и уровня оптимизации компилятора, я добавил специальную процедуру тестирования на этапе конфигурирования DataparkSearch, выбирающую только те новые варианты функций, которые исполняются быстрее на платформе, где производится установка. Это позволяет получить максимальную производительность DataparkSearch на каждой платформе.
Также я выделил эти функции в отдельную библиотеку, libdp, которая может быть установлена на ваш ПК отдельно и использоваться для ускорения любой динамически слинкованной программы (через переменную окрежения LD_PRELOAD). Например:
LD_PRELOAD=/usr/local/dpsearch/lib/libdp-4.so perl programm.pl
Сравнение теста производительности PerlBench для интерпретатора Perl, запускаемого на процессоре Intel Celeron M под управлением ОС Ubuntu Linux 10.04. Конфигурция A запускает системный интерпретатор Perl как /usr/bin/perl, конфигурация B запускает тот же интерпретатор как /usr/bin/perl5.10.1, конфигурация C запускает системный Perl с библиотекой libdp, предварительно загруженной при помощи переменной окружения LD_PRELOAD. Небольшие отличия в производительности в пределах 1-2% могут рассматриваться как случайные флуктуации, а соответствующие тесты выполняемыми с одинаковой производительностью.
Сравнение теста производительности rjsh-pybench для системного интерпретатора Python, запускаемого на том же ноутбуке без (benchmark p0) и с (benchmark p1) предварительно загруженной библиотекой libdp.
PYBENCH 1.4 Benchmark: p1 (rounds=20, warp=1) Comparing with: p0 (rounds=20, warp=1) Tests: min run cmp run avg run diff ----------------------------------------------------------------------------- BuiltinFunctionCalls: 169.50 ms 159.50 ms 173.80 ms +6.27% BuiltinMethodLookup: 179.00 ms 179.00 ms 190.12 ms -0.00% CompareFloats: 289.00 ms 289.00 ms 300.25 ms +0.00% CompareFloatsIntegers: 239.00 ms 219.50 ms 245.63 ms +8.88% CompareIntegers: 219.00 ms 218.50 ms 228.90 ms +0.23% CompareInternedStrings: 217.00 ms 217.00 ms 226.40 ms +0.00% CompareLongs: 209.00 ms 208.50 ms 213.35 ms +0.24% CompareStrings: 277.50 ms 277.50 ms 285.00 ms +0.00% CompareUnicode: 218.50 ms 218.50 ms 223.83 ms +0.00% ConcatStrings: 139.50 ms 159.50 ms 156.62 ms -12.54% ConcatUnicode: 169.50 ms 189.50 ms 185.28 ms -10.55% CreateInstances: 189.00 ms 189.00 ms 193.50 ms +0.00% CreateNewInstances: 1117.00 ms 1127.00 ms 1141.15 ms -0.89% CreateStringsWithConcat: 198.50 ms 208.50 ms 201.85 ms -4.80% CreateUnicodeWithConcat: 179.50 ms 209.50 ms 196.13 ms -14.32% DictCreation: 179.00 ms 179.00 ms 186.83 ms +0.00% DictWithFloatKeys: 199.00 ms 199.00 ms 206.60 ms -0.00% DictWithIntegerKeys: 218.00 ms 218.00 ms 224.75 ms +0.00% DictWithStringKeys: 317.00 ms 317.00 ms 326.80 ms +0.00% ForLoops: 179.50 ms 189.50 ms 195.80 ms -5.28% IfThenElse: 258.00 ms 258.00 ms 271.63 ms +0.00% ListSlicing: 289.00 ms 289.00 ms 297.30 ms +0.00% NestedForLoops: 449.50 ms 449.50 ms 467.98 ms +0.00% NormalClassAttribute: 248.00 ms 249.00 ms 254.55 ms -0.40% NormalInstanceAttribute: 248.50 ms 248.50 ms 253.50 ms +0.00% PythonFunctionCalls: 289.00 ms 289.00 ms 294.23 ms -0.00% PythonMethodCalls: 279.50 ms 279.50 ms 291.72 ms +0.00% Recursion: 179.50 ms 179.50 ms 192.52 ms +0.00% SecondImport: 868.00 ms 888.50 ms 884.02 ms -2.31% SecondPackageImport: 119.50 ms 119.50 ms 127.45 ms +0.00% SecondSubmoduleImport: 129.50 ms 129.50 ms 138.88 ms +0.00% SimpleComplexArithmetic: 189.50 ms 199.00 ms 203.45 ms -4.77% SimpleDictManipulation: 308.50 ms 308.50 ms 322.00 ms +0.00% SimpleFloatArithmetic: 348.00 ms 348.50 ms 358.18 ms -0.14% SimpleIntFloatArithmetic: 268.00 ms 268.00 ms 277.42 ms +0.00% SimpleIntegerArithmetic: 188.50 ms 188.50 ms 195.37 ms +0.00% SimpleListManipulation: 268.50 ms 258.50 ms 275.75 ms +3.87% SimpleLongArithmetic: 189.50 ms 179.00 ms 198.60 ms +5.87% SmallLists: 148.50 ms 148.50 ms 153.90 ms -0.00% SmallTuples: 179.00 ms 169.50 ms 183.95 ms +5.60% SpecialClassAttribute: 199.00 ms 199.00 ms 202.32 ms +0.00% SpecialInstanceAttribute: 279.00 ms 279.00 ms 285.30 ms -0.00% StringMappings: 259.00 ms 259.00 ms 266.23 ms -0.00% StringPredicates: 235.50 ms 235.50 ms 246.42 ms -0.00% StringSlicing: 128.50 ms 139.00 ms 138.25 ms -7.55% TryExcept: 198.00 ms 198.50 ms 202.45 ms -0.25% TryRaiseExcept: 129.00 ms 129.00 ms 135.25 ms +0.00% TupleSlicing: 289.50 ms 299.00 ms 305.12 ms -3.18% UnicodeMappings: 229.00 ms 239.00 ms 247.88 ms -4.18% UnicodePredicates: 244.50 ms 244.50 ms 253.53 ms -0.00% UnicodeProperties: 186.50 ms 186.00 ms 194.32 ms +0.27% UnicodeSlicing: 109.50 ms 129.00 ms 122.97 ms -15.12% ----------------------------------------------------------------------------- Notional minimum round time: 13036.00 ms 13156.50 ms -0.92%
Различия в менее, чем 1% могут также рассматриваться как случайные флуктуации.
Уведомление: Tweets that mention Небольшое ускорение -- Topsy.com
А что за функции libc?
Ok, увидел кое-что. То есть речь идет исключить о cycle unfolding, или что-то еще используется для ускорения?
Еще используется выравнивание на границу длинного слова при копировании произвольного участка памяти, а потом собственно копирование длинными словами. А также возможности pipeline, когда процессор подготавливает данные для последующих команд при выполнении текущей, если они независимы по данным и результатам работы друг друга.
Возможности pipeline на уровне развертывания цикла или что-то большее?
Да, в основном развертывание циклов. А что там может быть большее, есть какие либо примеры под рукой?
Вот это я и хотел узнать. Еще можно, конечно, использовать SSE инструкции, но будет работать только под Intel и AMD64
Кстати, я добавил тестирование реализаций при конфигурировании, на 64-битном AMD процессоре под Debian никакого ускорения не получается, а вот на Intel Celeron M или на том же AMD64, но под FreeBSD, получается быстрее.
Возможно у Debian есть ассемблерная реализация функций libc (может и не всех), которая линкуется, если выбрана опция -O2 или -O3.
Многие intrinsics заменяются на специальные эффективные команды процессора. Плюс на новых моделях процессорах, выравнивание по границе слова не увеличивает скорость доступа.