LINUX.ORG.RU

Производительность; илитный запил оптимальных реализаций и основы матчасти.

 , , ,


21

17

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

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

Изначально я хотел написать про то: что такое бесплатные вычисления на примере is_range() + сумма елементов массива, но тут выявилась смешная особенность, поэтому пока без is_range().

Начнём с простого - сумма елементов(float) массива. Как написать её быстро? Обычный крестопоц сделает так:

auto summ = accumulate(begin(vec), end(vec), 0.)

Этот код выдаёт 5.6GB/s(мы всё бенчим в л1д 32килобайта массив). Казалось бы, если бы мы слушали всяких «гуру», которые нам говорят: accumulate() - оптимизирован, «ты что умнее создатели stl"а?», «конпелятор умнее тебе - сам всё делает оптимально», «руками что-то делать слишком сложно и не нужно» - то мы бы там и остались с этими 5.6ГБ, но мы пойдём дальше и поймём почему так, и является ли это тем, что намн ужно.

Но посмотрев на код - он не векторизован:

	addq	$4, %rdx
	vcvtss2sd	-4(%rdx), %xmm2, %xmm2
	vaddsd	%xmm2, %xmm1, %xmm1

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

Поэтому конпелятор НЕ ВЕКТОРИЗУЕТ флоат по умолчанию, ну никак. Даже такую банальщину.

Для решения этих проблем - есть ключик -funsafe-math-optimizations, который входит в -ffast-math, который кладёт на точность при вычислениях. Добавив его мы получаем уже 44.9GB/s.

Но теперь мы получаем ещё одну проблему - надо думать: «как бэ сунуть эту ключик не повредив там, где этот ключик не нужен».

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

double memadd_autovec(buf_t buf) { //5.609465GB/s, либо 44.969652GB/s с ffast-math
  float * it = buf_begin(buf), * end = buf_end(buf), summ = 0.;
  do {
    summ += *it++;
  } while(it != end);
  return summ;
}

double hsumf(__v8sf v) {
  return (v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7]);
}

double memadd_vec(buf_t buf) { //45.652002GB/s и класть на ffast-math
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ += *it++;
  } while(it != end);
  return hsumf(summ);
}

Т.е. разницы никакой нет, кроме нужной нам реализации горизантального сложение вектора. Когда я говорил пацану: «векторную сишку для написания быстрого кода юзать намного проще, чем плюсы» - поцан нипонимэ, да и любые пацаны скажут - ну дак с -ffast-math оба выдают по 45гигов - нахрен эта сишка нужна?

А вот зачем:

double memadd(buf_t buf) { //132.878440GB/s
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
  } while(it != end);
  return hsumf(summ);
}

Это называется пацанский анролл копипастой, а вот заставить конпелятор нормально что-то разанролить очень сложно.

Если бы мы слушали всяких «гуру», которые нам вещают: «анрол говно и не нужен» - мы бы так и седели с 45-ю гигами, а так мы сидим с 132.878440GB/s. Т.е. анролл нам дал немного не мало ~300%.

Но основная мысль, которую толкают всякие «гуру» - это не надо следить за тактами/считать такты и прочее. Но мы о5 сделаем наоборот и посмотрим что будет.

Т.к. наш юзкейс упирается на 99% в throughput и дёргается одна инструкция, то нам достаточно просто считать теоретическую производительность для моего камня. 4.5(частота камня)*8(т.е. у нас камень с avx, то там вектор 32байта, либо 8флоатов.)*1(throughput нашей инструкции - в данном случае vpaddps из интел мануала). Т.е. 36гигафлопс, либо ~144гига. Т.е. мы сняли овер 90% теоретической производительности - остальные 10% у нас ушли в наши циклы, всякие горизонтальные суммы вектора и прочее, ну и конечно же чтение данных из кеша.

Но самое смешное - на моём хасвеле умножение имеет throughput 0.5 - т.е. на хасвеле умножение быстрее сложения. Это новая забористая трава у интела.

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

Поэтому очень смешно слушать, когда какие-то пацаны говорят: «float point имеет такую же производительность как и инты» - нет, оно имеет такоу же производительность лишь по причине того, что на штеуде инты тормазят так же, как и float.

И чтобы окончательно в этом убедится - мы взглянем на fma(вариации умножения со сложением/вычитанем), которые имеют throughput 0.5 - да, да - на хасвеле умножение+сложение в 2раза быстрее просто сложения. Это уже не просто трава - это что-то принципиально новое.

У целочисленного сложения же throughput 0.5 и казалось бы, если мы поменяем в нашей функции float на int - у нас будет сложение работать в 2раза быстрее, но это не так. Оно выдаёт те же 130гигов, а почему?

Вообще у камня есть такая фича, допустим у нас:

add $1, %reg0//вот тут инструкция add залочит регистр reg0
add $1, %reg0//а эта инструкция уйдёт в лок до особождения предыдущей инструкцией регистра reg0

Чтобы такой жопы небыло - есть специальная фича:

add $1, %reg0//lock reg0
add $1, %reg0//И тут вместо того, чтобы уйти в лок - камень вместо reg0 даёт инструкции любой свободный регистр.

Эта фича называется прееименование регистров, либо как-то так - мне лень гуглить.

Дак вот штука в том, что фича работает через жопу. Мне лень читать мануал и искать почему так, но штука в том, что она ограничивает throughput. На умножении и целочисленном сложении она огранивает throughput c 0.5 до 1.

И вот я решил заюзать сложении через fma:

__v8sf fmaadd(__v8sf a, __v8sf b) {
  return _mm256_fmadd_ps(_mm256_set1_ps(1.), a, b);// a + b * 1. == a + b.
}

double memadd_fma(buf_t buf) {
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ = fmaadd(summ, *it++);
  } while(it != end);
  return hsumf(summ);
}

Но меня ждала жопа: 27.347290GB/s, причем не анролл и ничего не помогал. Я уж подумал, что мануал наврал, но позже до меня допёрло: у неё latency 5тактов и ((4.5×8)÷5)×4 ~= 29гигов - т.е. я получаю производительность с её latency, но какой жопой оно так?

Потом я вспомнил, что гцц гинерит анрольный код вида:

add $1, %reg0
add $1, %reg0
//а не
add $1, %reg0
add $1, %reg1

Т.е. на неё вообще не работает переименовывание регистров - и инструкции постоянно в локе. Я это проверил и оказался прав. Ну и я написал такой мемадд:


__v8sf fmaadd(__v8sf a, __v8sf b) {
  return _mm256_fmadd_ps(_mm256_set1_ps(1.), a, b);
}

inline void fma_10way_finality(__v8sf * cache, __v8sf * it, __v8sf * end) {
  switch(end - it) {
    case 8:
      *(cache + 7) = fmaadd(*(cache + 7), *(it + 7));
      *(cache + 6) = fmaadd(*(cache + 6), *(it + 6));
    case 6:
      *(cache + 5) = fmaadd(*(cache + 5), *(it + 5));
      *(cache + 4) = fmaadd(*(cache + 4), *(it + 4));
    case 4:
      *(cache + 3) = fmaadd(*(cache + 3), *(it + 3));
      *(cache + 2) = fmaadd(*(cache + 2), *(it + 2));
    case 2:
      *(cache + 1) = fmaadd(*(cache + 1), *(it + 1));
      *(cache + 0) = fmaadd(*(cache + 0), *(it + 0));
    case 0:
      break;
    default: error_at_line(-1, 0, __FILE__, __LINE__, "bad_aligned");
  }
}

double memaddfma_10way(buf_t buf) {
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = (__v8sf){};
  __v8sf * cache = (__v8sf[10]){{}};
  uint64_t i = 0;
  while((it += 10) <= end) {
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    *(cache + i) = fmaadd(*(cache + i), *(it - i - 1));++i;
    i = 0;
  }
  fma_10way_finality(cache, (it - 10), end);
  summ = (*(cache + 0) + *(cache + 1) + *(cache + 2) + *(cache + 3) +
	  *(cache + 4) + *(cache + 5) + *(cache + 6) + *(cache + 7) +
	  *(cache + 8) + *(cache + 9));
  return hsumf(summ);
}

Пришлось хреначить финалити, ибо тут «анролл» на 10, а почему на 10 - для максимального throughput"а - надо, чтобы каждый каждый регистр юзался через 5тактов - т.е. 10регистров.

И вся эта порятнка нужна для борьбы с тупостью конпелятора.

Это уже: 214.167252GB/s(раельно там в районе 250 - просто мой бенч говно). 107 гигафлопс на ведро. Из теоретических 144, но тут уже влияние кеша. Причем 50+ из которых выкидываются и просто бесплатные.

Теперь вопрос к пацанам - что нам дадут эти гагфлопсы, когда у нас будет массив не 32килобайта, а 32мегабайта? Зачем нужно выживать максимум, когда скорость памяти отсилы 20-30гигабайт и нам хватит даже С++ кода с ffast-math?

Ну и призываются упомянутые мною пацаны: mv - этот тот експерт, что вещал про «руками переименовывать регистры не надо» и «анрол ваще ненужен», emulek вещал про ненужность счёта тактов, и не понимал что такое «беслпатно», AIv - не понимал в чем проблема плюсов, ck114 - так же не понимал в чем проблема плюсов.

Бенчи: https://gist.github.com/superhackkiller1997/606be26fa158ef75501d - вроде я там ничего не напутал.

P.S. - не выпиливайте пж, пусть пацаны «нужно» или «не нужно». Мне интеерсно. Ну и там рекомендации пацанов.



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

это ничего не меняет. Проблема носит качественный, а не количественный характер. Вот если-бы у тебя было 3 операции, то замена на double помогла(в большинстве случаев, но не всегда). Но у тебя не 3, а 32768.

Как же меня одалела твоя тупость. 0.0001 мы складываем 100500раз, по сортировочки, а потом добалвяем 1.e7f и вуаля - твоя «техника поомгла».

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

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

В любом случае точность у тебя будет отсилы 10%, и этим результатом ты можешь только подтерется.

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

Т.е. число 0.0001 -4-й порядок и число 0.001 -3-й, если ты будешь складывать больше 10ти(в данном случае) чисел с -4-м порядком - ты получишь 0.001 - т.е. -3-й порядок.

Ты понимаешь, ламерюга, в чем суть того, о чем ты кукарекаешь? Ты понимаешь в каких случаях это работает? Перенос порядка происход только ПРИ ПЕРЕПОЛНЕНИИ предыдущего порядка - это основа.

И это ПЕРЕПОЛНЕНИЕ должно быть В РАЙОНЕ ТОЧНОСТИ СЛЕДУЮЩЕЙ ГРУППЫ, а если оно ВНЕ ТОЧНОСТИ - смысла в твоей байде нет.

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

детка, это не я придумал. Все так делают, ибо иначе, «результатом» можно только подтереться. И делают так вовсе не после распространения SIMD, а ещё с тех пор, когда тебя в проекте не было.

Ещё раз. Скложи мне 1e32 + 1e24 + 1e16 + 1e8 + 1e0 + 1e-8 + 1e-16 + 1e-24 + 1e-32, а я поржу.

Все так делают, ибо иначе, «результатом» можно только подтереться.

Как я люблю, когда нули цепляются за всех. Я потерплю твою нулёвость, атк уж и быть. Вот когда ты складываешь числа e-6 и числа e5, то для полного представления их суммы тебе надо минимум 12порядков + то, что уйдёт влево.

Но сумма будет у тебя самого левого порядка- т.е. e-6 минимум, а остальные 6порядков(e-1 - e-6) у тебя отсекутся. Т.е. у тебя уже будет результат «которым ты можешь подтерется» в любом случае.

И чтобы твоя байда сработала - и «битики» с порядка e-6 дошли до e0(граница точности e5) - тебе надо минимум 1e0/9e-6 чисел - т.е. в районе 100500. Если же у тебя будет на одно число меньше, чем 1e0/9e-6, либо какое-нибудь из чисел будет меньше 9e-6 - тебе даже твоя байда не поможет.

Суть не в том, что кто-то. Суть в том, что ты ламерок даже 200метров не выжмешь, именно ты.

И зачем ты кукарекашь про симды, о которых ты нихренан е знаешь?

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

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

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

Но это «таблица умножения». Если кто-то собирается оперировать данными, разрядность которых еле-еле влазит в выбранный формат (в мантиссу), и ничего не предпринимает для контроля порядка оперирования этими числами (и если ему важна точность) - он ССЗБ.

Для «нормализованных» данных программа работает? Работает. Для ненормализованных данных ни один «простейший» вариант не годится, но любой может быть использован «внутри» расширенного алгоритма. Универсальный способ сложения набора «флоатов» с максимальной точностью только один - расширение мантиссы. Но к обсуждаемой задаче это не относится :)

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

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

Я описал в какик случаях порядок будет влиять. Ты хоть мильярды чисел 1e-20 складывай - прибавя к ним 1e6 - ты потеряешь всё то, что ты там складывал. Сортировка должна тебе дать цепочку, благодаря которой разряды не будут отсекаются, а будут иметь возможность на то, что их сумма перетечёт в следующий разрят, и уже не будет обрезанна.

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

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

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

Но это «таблица умножения». Если кто-то собирается оперировать данными, разрядность которых еле-еле влазит в выбранный формат (в мантиссу), и ничего не предпринимает для контроля порядка оперирования этими числами (и если ему важна точность) - он ССЗБ.

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

Для «нормализованных» данных программа работает? Работает. Для ненормализованных данных ни один «простейший» вариант не годится, но любой может быть использован «внутри» расширенного алгоритма.

Мне похрен что там работает - сложение флоатов - это пример, и мне покласть работает он или нет. Придирка к точности - это единственное оправдание, которое ламерки типа емулеки юзают воимя оправдания своей анскильности и возможности покукарекать и меня в чем-то уличить.

Изначально это вообще был мемадд - складывание 2-х массивов, но я посчитал это слишком сложным для эмулеков, ибо там надо пилить в вариации кеш/рама.

Carb_blog
() автор топика
Ответ на: комментарий от no-such-file

Ну дак он там кукарекал «всегда работает» - должно работать - инфа соточка.

Иди перечитай своего дружка-питушка, не он ли кукарекал «только так, иначе подтерется»?

Можешь там не по одному числу складывать, авось памяти хватит и тебе «всегдаработает» даст профит.

Что ты там со своей фпгашкой? Досихпор веришь, что в 1000раз быстрее x86? Тебе же инстересно, давай следующий бложик сделаем про твои считалочки? Проверим х86, а?

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

Что ты там со своей фпгашкой?

А? Ты меня с mv перепутал.

Ну дак он там кукарекал «всегда работает» - должно работать - инфа соточка.

А кто сказал, что переполнение - это «не работает»? Документированное поведение для float - всё работает как задумано.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

А? Ты меня с mv перепутал.

А не ты ли лабу писал на фпгашке? Ты точно со мною спорил про обходы/локальность в теме alv, авот про лабу на фпгашке я не уверен.

А кто сказал, что переполнение - это «не работает»? Документированное поведение для float - всё работает как задумано.

Оно так же работает и в моём примере, но емулеку о но не работает по причине того, что результатом можно подтретеся. Вот тут тоже не работает, ибо результатом можно подтерется.

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

Оно так же работает и в моём примере

Но на твоём примере не работают другие случаи. Просуммируй 1.234567 32к раз. Только не надо говорить, что суммировать тут не нужно, а можно просто умножить - тест есть тест.

Ты точно со мною спорил про обходы/локальность в теме alv

Да, было дело. Ты там упарывался и доказывал, что вычисления на пуле коротких массивов (типа такой список, но «анроллнутый») быстрее, чем на просто монолитном массиве. Странно, что в этой теме я не вижу никаких пулов и списков.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от Carb_blog

Изначально это вообще был мемадд - складывание 2-х массивов, но я посчитал это слишком сложным для эмулеков, ибо там надо пилить в вариации кеш/рама.

Ну так перестань спорить и давай его сюда! :)

yyk ★★★★★
()
Ответ на: комментарий от no-such-file

Но на твоём примере не работают другие случаи.

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

10113.577148//моё
10113.572864//умножение

Ты там упарывался и доказывал, что вычисления на пуле коротких массивов (типа такой список, но «анроллнутый») быстрее, чем на просто монолитном массиве.

Упоролсячтоли? Он спрашивал «как бы заюзать быстрый вектор, чтобы не тормазил на реалоке и не „жрал память“» - я ответил - юзай malloc(1000500000);

Вы там начали кукарекать про то, что malloc(1000500000) не круто и прочее.

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

Я тебе предлогал тест - возми пулл страниц и записывай данные через одну - она будет работать так же.

Нехрен мне тут рассказывать - у меня идеальная память, я максимум ники/имена/названия могу не вспомнить сразу.

И да, ты что мне отвечаешь - я спорил с каким-то студентом, который говорил про в1000раз сливаю х86 на фпга. Почему-то я думаю, что это был ты. Это был ты?

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

Просуммируй 1.234567 32к раз.

10113.577148//моё
10113.572864//умножение

Ну ты чё, даже умножить не в состоянии? 1.234567*32000=39506.144000, а 1.234567*(32*1024)=40454.291456. Даже близко не лежит, что ты там суммировал то? И да, покаж полный пример кода.

no-such-file ★★★★★
()
Ответ на: комментарий от Carb_blog

Почему-то я думаю, что это был ты. Это был ты?

Странный вопрос при такой идеальной памяти, и нет, это был не я.

локально больше страницы смысла почти не имеет

Вот. А я утверждаю, что имеет.

Я тебе предлогал тест - возми пулл страниц и записывай данные через одну - она будет работать так же.

Вот ты и возьми, и запили своё сложение по пулу страниц, а не по массиву. Будет работать также?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

запили своё сложение по пулу страниц, а не по массиву.

Чем «пул страниц» отличается от mmap анонимной памяти (с MAP_POPULATE)?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от no-such-file
40454.292969
40454.291456

В килобайтах хреначь, а не в числах. Да какая разница сколько - оно будет давать правильный результат. Тут плывёт флоат.

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

В пуле страницы идут не подряд, а как попало. Для линейного доступа нужно транслировать индекс «массива» в адрес конкретного пула+смещение в пуле. И это, утверждается, что ни разу не медленнее, чем простой, дубовый массив.

no-such-file ★★★★★
()
Ответ на: комментарий от Carb_blog

Да какая разница сколько - оно будет давать правильный результат. Тут плывёт флоат.

Ну, эта, давай не для степени двойки. 32000 или 8000. И дал бы уже полный код, я б сам посмотрел что получается.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

В пуле страницы идут не подряд, а как попало.

«Как попало» по виртуальному адресу или по физическому? Если по физическому, то это не имеет значения с MAP_POPULATE; если по виртуальному, то нам придется вручную делать переходы между страницами - понятно, что из-за этого мы что-то потеряем.

Для линейного доступа нужно транслировать индекс «массива» в адрес конкретного пула+смещение в пуле

Еще раз: виртуальные адреса пула непрерывны и линейны?

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

Да какая разница сколько - оно будет давать правильный результат. Тут плывёт флоат.

Есть разница. Кстати, я сейчас допёр, ты же считаешь сумму частями по 8 флоатов - этим спасаешься, в данном конкретном примере.

Надо таки считать по рандомным числам, как емулек предлагал.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Потери на расчете переходов очевидны.

Не так очевидны, в той теме в вектор докидывали данные. Что быстрее: медленная реалокация вектора с последующим быстрым расчётом, или быстрое докидывание в deque с последующим медленным расчётом? Я был за то, что первый вариант в большинстве случаев быстрее, т.к. в основном время жрут расчёты. А если расчётов так мало, что есть преимущество deque, то время работы и так будет маленькое и можно не заморачиваться.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Что быстрее: медленная реалокация вектора с последующим быстрым расчётом, или быстрое докидывание в deque с последующим медленным расчётом?

Эта задача не имеет отношения к сабжу.

tailgunner ★★★★★
()
Ответ на: комментарий от no-such-file

Странный вопрос при такой идеальной памяти, и нет, это был не я.

Патамучто я не помню как вас там всех зовут.

Вот. А я утверждаю, что имеет.

double memadd4096(buf_t buf) {
  __v8sf * it = buf_begin(buf), * end = buf_end(buf), summ = {};
  do {
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128*4 512
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;//32*4 128
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    summ += *it++;summ += *it++;summ += *it++;summ += *it++;
    it += 128;
  } while(it != end);
  return hsumf(summ);
}

21ГБ/с нормально
20.5ГБ/с через страницу

Там можно ещё поиграться, но результат понятен.

Вот ты и возьми, и запили своё сложение по пулу страниц, а не по массиву. Будет работать также?

Да.

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

Он просто ракал, который переиначивает мои слова.

Пулл страниц - это

void * get(void) {
  static base = bla-bla;
  void * ret = base;
  base += 4096;
  return ret;
}

Вот мы вместо одного гет, как в массиве - делаем гет через 1 и пишем 10101010.

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

Он сказал «как попало», т.е. в случайном порядке, а ты делаешь через 1.

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

А чёж он массив не читает в случайном порядке?

У тебя же 5звёзд - ты же можешь читать удалённые месаги? Вот перечитай наш спор. Если можешь - я тебе его даже найду.

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

какой жопой в случйаном порядке?

Ну так ты же предлагал динамически навыделять страниц. Где будут выделены эти страницы в общем случае не предсказуемо.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Какие страницы? Кого выделять? Кого предлагал? Иди ради интереса перечитай - что я думаю о «динамическом» и «рандомном» - это описывается мою крайне красочно в каждой теме, где я отписывался.

Какая нахрен непредсказуемость, чего навыделять - хреначь malloc(10005000) - пиши в любую, ничего не поменяется.

И иди погугли что такое pagefault, и почему рандомность не бенчится и не имеет смысла.

Ещё раз тебе повторю - локальность на уровне большей страницы не имеет смысла. Если ты не будешь «полностью» заполнять страницы - ты будешь дёргать их чаше, а попадать в dtlb реже. Это единственное, что ты можешь запартачить.

А с какими адресами связаны страницы - покласть, хоть через 1, хоть через 100. Ты только тратишь vmem - всё.

Но это уже проблема твоих рук, а не локальности.

Carb_blog
() автор топика
Ответ на: комментарий от no-such-file

Есть разница. Кстати, я сейчас допёр, ты же считаешь сумму частями по 8 флоатов - этим спасаешься, в данном конкретном примере.

Нет, ты не допёр - там 80аккамуляторов, а не 8.

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

так с матрицами ты слил, да?

А ты думаешь, что человек, который не знает, что такое матрицы, в принципе может что-то там напрограммировать?

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

А ты думаешь, что человек, который не знает, что такое матрицы, в принципе может что-то там напрограммировать?

я думаю, что он в школе учился, и про СЛАУ ему рассказывали.

Или СЛАУ из школьной программы исключили? Когда я учился(в 80х), СЛАУ было. Даже с тремя переменными.

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

какую-то уету в школе сейчас проходят. На выходе имеем ТСа и подобных...

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