Size: a a a

2020 May 29

ПФ

Паша Финкельштейн... in Moscow Spark
Nikolay
на стэке какого вызова? она в хипе лежит ведь так как это масив
даже это не оязано быть правдой. Представь себе что у тебя массив из 3х интов. Каждый из них используется в каком-то месте и не меняется в массиве. Потенциально мы можем выкинуть массив и просто прокидывать эти инты через стэк
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Это сложная оптимизация. Простая оптимизация — выкинуть обёртку в виде InternalRow и работать с самим массивом, пользуясь тем, что в ассемблере нет типов
источник

ПФ

Паша Финкельштейн... in Moscow Spark
тогда на стэке будет указатель на массив в хипе, конечно
источник

N

Nikolay in Moscow Spark
Паша Финкельштейн
Это сложная оптимизация. Простая оптимизация — выкинуть обёртку в виде InternalRow и работать с самим массивом, пользуясь тем, что в ассемблере нет типов
там обращение идет через медоты с несколькими параметрами. в самих методах кроде доступа есть еще проверки. нельзя просто так его выкинуть компилятором этот кусок кода и заменить на доступ база+смещение. или какая другая идея в этом?
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Nikolay
там обращение идет через медоты с несколькими параметрами. в самих методах кроде доступа есть еще проверки. нельзя просто так его выкинуть компилятором этот кусок кода и заменить на доступ база+смещение. или какая другая идея в этом?
можно, если звёзды сошлись
источник

ПФ

Паша Финкельштейн... in Moscow Spark
То есть если у тебя на самом деле всегда одно и то е передаётся кроме индекса массива — то одно и то всё что внутри моно заинлайнить в безумловные переходы
источник

ПФ

Паша Финкельштейн... in Moscow Spark
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Если присмотреться — окажется что InternalRow вообще не используется!
источник

N

Nikolay in Moscow Spark
Паша Финкельштейн
Если присмотреться — окажется что InternalRow вообще не используется!
localtablescan_row_0.getInt(0) - вот он вызов
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Nikolay
localtablescan_row_0.getInt(0) - вот он вызов
Это да, я имею в виду что InternalRow прокидывается дальше, но не используется. А getInt(0) — как раз оптимизируемая операция потому что там всегда будет int, а не String, например
источник

ПФ

Паша Финкельштейн... in Moscow Spark
а ещё примечательно что конкретно в этом случае можно просто взять и переложить данные из InternalRow в mutable state :)
источник

ПФ

Паша Финкельштейн... in Moscow Spark
точнее не так. internalrow.get(0) . map . write (0)
источник

ПФ

Паша Финкельштейн... in Moscow Spark
К вопросу об оптимальности сгенерированного кода
источник

N

Nikolay in Moscow Spark
Паша Финкельштейн
Это да, я имею в виду что InternalRow прокидывается дальше, но не используется. А getInt(0) — как раз оптимизируемая операция потому что там всегда будет int, а не String, например
оно прокидывается только туда, где может понадобиться. в map оно уже не нужно. поэтому там его нет. оно может понадобится только в deserializetoobject и поэтому туда и прокинули. может компилятор и сможет оптимизировать getInt(0), но это не выглядит простой задачей. массив каждой строки в разных местах ведь. и ему еще надо понять, что функции проверки по индексу( который в данном случае 0)  иденпотенты.
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Nikolay
оно прокидывается только туда, где может понадобиться. в map оно уже не нужно. поэтому там его нет. оно может понадобится только в deserializetoobject и поэтому туда и прокинули. может компилятор и сможет оптимизировать getInt(0), но это не выглядит простой задачей. массив каждой строки в разных местах ведь. и ему еще надо понять, что функции проверки по индексу( который в данном случае 0)  иденпотенты.
Конечно, но и потимизации у тебя разные на каждом пути. В рамках конкретного пайплайна путь исполнения может быть и один (как тут)
источник

ПФ

Паша Финкельштейн... in Moscow Spark
А насчёт непростой задачи — я бы даже сказал что она очень сложная и поэтому это многолетняя работа ребят из Oracle Labs, которая вот сейчас вылилась в грааль JIT
источник

N

Nikolay in Moscow Spark
Паша Финкельштейн
Конечно, но и потимизации у тебя разные на каждом пути. В рамках конкретного пайплайна путь исполнения может быть и один (как тут)
а как он поймет, что функции проверки можно отбрросить?   private void assertIndexIsValid(int index) {
   assert index >= 0 : "index (" + index + ") should >= 0";
   assert index < numFields : "index (" + index + ") should < " + numFields;
 }
источник

ПФ

Паша Финкельштейн... in Moscow Spark
Там же счётчик. Как у тебя не проверяются на самом деле каждый раз границы массива. Считаем сколько раз мы попали в границы, если попали, например 1000 — компилируем этот буть в машинный коди ходим по нему. Как только словили ошибку доступа — деоптимизируем всё нахер, скатываемся в этом месте в интерпретацию (C0 то есть) и иди по интерпретируемому пути с проверками границ. Как только в границы не попали — кидаем исключение
источник

ПФ

Паша Финкельштейн... in Moscow Spark
То есть это буквально то, как работает tiered compilation в JVM
источник

N

Nikolay in Moscow Spark
Паша Финкельштейн
Там же счётчик. Как у тебя не проверяются на самом деле каждый раз границы массива. Считаем сколько раз мы попали в границы, если попали, например 1000 — компилируем этот буть в машинный коди ходим по нему. Как только словили ошибку доступа — деоптимизируем всё нахер, скатываемся в этом месте в интерпретацию (C0 то есть) и иди по интерпретируемому пути с проверками границ. Как только в границы не попали — кидаем исключение
там дочтуп через unsafe - UNSAFE.getInt. не уверен, что он поймет, что папали за границу. поэтому они там и сделали кастомную проверку руками на границу достпупа, которую выкинуть значит нельзя
источник