Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 09:14
Оценка:
Можно ли делать вставки MSIL в код на c# ? По аналогии, как в C++ можно сделать ассемблерную вставку в код.
Возник такой вопрос, потому что, программа написанная на C# не использует полные арифметические возможности процессора.
У меня программа, будет работать с длинными целыми.

Будет тип,

struct UInt128
{
  UInt64 high;
  UInt64 low;
}


Чтобы определить операции умножения и деления двух экземпляров UInt128, очевидно, придется перемножить (или разделить) пары UInt64 внутри этого типа,
затем складывать промежуточные результаты, и в итоге, записывать верхнюю и нижнюю UInt64-части, внутри типа UInt128.
К примеру, для умножения, имеем,

UInt128 a;
UInt128 b;


Первый промежуточный результат — перемножим два UInt64-типа, a.low * b.low. В итоге, получим результат — 128-битное число, в виде двух 64-битных чисел.
Процессор позволяет это сделать одной ассемблерной инструкцией mul — результат, в регистрах RDX:RAX, причем в RDX — старшие 64 бита, а в RAX — младшие 64 бита.

И вот, в этот момент, нет возможности (или по крайней мере, мне неизвестно как) средствами c# прямо и получить эту старшую часть — которая уже содержится в регистре RDX !
(только часть RAX и будет в результате получена — в произведении, которое тоже имеет тип UInt64).
Чтобы получить старшую часть — нужно при перемножении двух UInt64 — их в свою очередь, разбивать
на два под-типа UInt32, и делать 4 умножения вместо одного, на уровне процессора.
От этого ниже производительность (а в некоторых задачах, в том числе моей, эти умножения-деления будут занимать весьма весомую часть), и не используются все возможности 64-битных процессоров.

(Аналогичная возможность и при делении, процессор позволяет разделить 128-битное содержимое RDX:RAX на 64-битное содержимое, к примеру RBX регистра, в то время,
как в C# можно делить только 64-битные числа, на 64-битные числа. Но пока — вопрос как хотя бы только умножение реализовать. Если это можно, то далее с MSIL вставками
можно и деление оптимизировать)

На c++ можно было бы просто сделать ассемблерную вставку, и в нужный момент, прочитать-таки, этот регистр RDX, после умножения, и не делать в программе
в 4 раза больше операций умножения, чем это необходимо на процессорном уровне.

Можно ли подобное сделать, с помощью вставки MSIL в код на C# ? Т.е. заставить после умножения сгенерировать такой машинный код, который прочитает регистр RDX
и запишет его в UInt64 переменную, и не надо было бы делать лишних умножений?

UInt64 a;
UInt64 b;
UInt128 result;
 
result.Low = (UInt64)(a * b);

{в этот момент в регистре RDX уже содержится старшие 64 бита, часть умножения (a * b). Нужно чтобы MSIL сгенерировал для 64-битных процессоров, аналогичный
result.High = RDX регистр

}

Заранее, большое спасибо.
Отредактировано 04.11.2016 22:07 VladD2 . Предыдущая версия .
Re: Можно ли делать вставки MSIL в код на c# ?
От: Sharov Россия  
Дата: 03.11.16 09:27
Оценка: +1 -1
Здравствуйте, SergeyY, Вы писали:


SY>Заранее, большое спасибо.


Ответ легко нагуглить, но думается, что такие вставки недопустимы.
Ну так пишите на с++ (хоть с соотв. библиотеками, хоть со вставками), и вызывайте этот код через interop.
Кодом людям нужно помогать!
Re: Можно ли делать вставки MSIL в код на c# ?
От: fddima  
Дата: 03.11.16 09:37
Оценка: +1
Здравствуйте, SergeyY, Вы писали:

SY>Можно ли делать вставки MSIL в код на c# ? По аналогии, как в C++ можно сделать ассемблерную вставку в код.

Агрессивный инлайнинг метода — уже вставка MSIL. Так что надо пробовать (MethodImplAttribute/Options, .net 4.6).
Однако в MSIL никакого x86-like div разумеется нет. Так что надо смотреть ещё что там он (JIT) за код генерирует по факту в релизной сборке.

Оно точно очень-очень нужно быть супер оптимальным? Если это числодробилка — C# всё равно сольет плюсам, и возможно имеет смысл задуматься об отдельном модуле. Если операции выполняются эпизодически — то лучше уж код попроще без издевательств.

Погуглите SO — там вроде есть и готовые решения, может подойдут.
Re[2]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 09:47
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, SergeyY, Вы писали:



SY>>Заранее, большое спасибо.


S>Ответ легко нагуглить, но думается, что такие вставки недопустимы.

S>Ну так пишите на с++ (хоть с соотв. библиотеками, хоть со вставками), и вызывайте этот код через interop.

А если написать на с++, и вызвать этот код через interop — не будет ли каких нибудь дополнительных накладных расходов в программе?
(по сравнению со случаем, если бы заставили CIL сгенерировать код).

MSIL (или CIL) однозначно в определенном месте сгенерирует асм-инструкцию MUL , и далее, после выполнения её, нам по сути нужно прочитать
содержимое регистра RDX и записать по адресу, где находится наша переменная, и всё!

В самом .NET есть же возможность даже сам компилятор дописывать, удивительно, вот и хотелось бы, просто использовать полностью арифметические
возможности процессора..
Re[2]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 09:55
Оценка:
Здравствуйте, fddima, Вы писали:

F>Здравствуйте, SergeyY, Вы писали:


SY>>Можно ли делать вставки MSIL в код на c# ? По аналогии, как в C++ можно сделать ассемблерную вставку в код.


F> Оно точно очень-очень нужно быть супер оптимальным?


Тут дело не супер-оптимальности. Дело в том, что если не использовать эти возможности процессора, то у нас количество умножений-делений, с длинной
арифметикой — увеличивается, причем сразу в 4 раза.

Если бы это не давало бы прироста производительности, то в прошлом и 64-битные регистры вообще не создавали бы, перемножали бы 32-битные числа
(тогда количество операций было бы в 16 раз больше), или и вовсе 16-битные (тогда количество операций было бы в 64 раза больше).

Я не гоняюсь за сверх-оптимальностью, но здесь выигрыш был бы существенный..
Re[3]: Можно ли делать вставки MSIL в код на c# ?
От: fddima  
Дата: 03.11.16 10:00
Оценка: +2
Здравствуйте, SergeyY, Вы писали:

SY>Я не гоняюсь за сверх-оптимальностью, но здесь выигрыш был бы существенный..

Здесь не нужно теории. Если у вас 1000 операций в секунду с этим типом — значит 4-х кратная "просадка" в микроскоп не видна. Если это именно что числодробилка и её можно отделить — то лучше постараться выделить в отдельный модуль. Да, накладные расходы будут на интероп, но значительно меньше чем выполнить миллиард делений особо извращенным (неэффективным) способом.

UPD: В интеропе не забываем SuppressUnmanagedCodeSecurityAttribute — толку от проверок обычно нет, а время жрут.
Отредактировано 03.11.2016 10:05 Mystic Artifact . Предыдущая версия . Еще …
Отредактировано 03.11.2016 10:03 Mystic Artifact . Предыдущая версия .
Отредактировано 03.11.2016 10:01 Mystic Artifact . Предыдущая версия .
Re: Можно ли делать вставки MSIL в код на c# ?
От: Sinix  
Дата: 03.11.16 10:05
Оценка: 2 (1) +3
Здравствуйте, SergeyY, Вы писали:

SY>У меня программа, будет работать с длинными целыми.


Нормальной быстрой математики под дотнет нет, большинство реализаций ничего кроме фейспалма не вызывают. Как пример.

Есть BigInteger, если устраивают тормоза в ~50x по сравнению с int64 — отлично. Если нет — остаются разнообразные обёртки типа MPIR.net, для совсем отчаянных есть gpgpu-обёртки типа CUDAfy.

Я бы вытащил числобробилку в натив и не мучался.
Re[4]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 10:07
Оценка:
Здравствуйте, fddima, Вы писали:

F>Здравствуйте, SergeyY, Вы писали:


SY>>Я не гоняюсь за сверх-оптимальностью, но здесь выигрыш был бы существенный..

F> Здесь не нужно теории. Если у вас 1000 операций в секунду с этим типом — значит 4-х кратная "просадка" в микроскоп не видна. Если это именно что числодробилка и её можно отделить — то лучше постараться выделить в отдельный модуль. Да, накладные расходы будут на интероп, но значительно меньше чем выполнить миллиард делений особо извращенным (неэффективным) способом.

F> UPD: В интеропе не забываем SuppressUnmanagedCodeSecurityAttribute — толку от проверок обычно нет, а время жрут.



Про интероп понятно, спасибо.
Re[3]: Можно ли делать вставки MSIL в код на c# ?
От: Sharov Россия  
Дата: 03.11.16 10:14
Оценка:
Здравствуйте, SergeyY, Вы писали:

SY>Здравствуйте, Sharov, Вы писали:


S>>Здравствуйте, SergeyY, Вы писали:



SY>>>Заранее, большое спасибо.


S>>Ответ легко нагуглить, но думается, что такие вставки недопустимы.

S>>Ну так пишите на с++ (хоть с соотв. библиотеками, хоть со вставками), и вызывайте этот код через interop.

SY>А если написать на с++, и вызвать этот код через interop — не будет ли каких нибудь дополнительных накладных расходов в программе?


Использовать interop для 2-х ассемблерных команд как-то странновато, согласен. С др. стороны у Вас "длинная" арифметика и там соотв. свои библиотеки и т.п. В данном случае оправдано.

SY>(по сравнению со случаем, если бы заставили CIL сгенерировать код).


Это самый быстрый вариант, безусловно. Вообще у ms появилось несколько jit'ов типа RyuJit и т.д. Можно посмотреть на них, может они и подойдут.
Кодом людям нужно помогать!
Re[2]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 10:15
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, SergeyY, Вы писали:


SY>>У меня программа, будет работать с длинными целыми.


S>Нормальной быстрой математики под дотнет нет, большинство реализаций ничего кроме фейспалма не вызывают. Как пример.


S>Есть BigInteger, если устраивают тормоза в ~50x по сравнению с int64 — отлично. Если нет — остаются разнообразные обёртки типа MPIR.net, для совсем отчаянных есть gpgpu-обёртки типа CUDAfy.


S>Я бы вытащил числобробилку в натив и не мучался.



Да, видимо придется вытаскивать весь код на C++, а ассемблерными вставками (кроме UI), производительность для задач алгоритмического характера — важнее всего.
Просто на C# много других полезных и приятных вещей, одна сборка мусора чего стоит.
Вот и было интересно — если бы можно было , добавить в генерируемый CIL код что то свое (в данном случае — хотя бы просто прочитать регистр RDX в нужный момент),
то я мог бы сделать библиотеку классов для работы с длинной арифметикой гораздо быстрее этих BigInteger-ов, и использовал бы все возможности 64-битных процессоров.
А если нельзя часть CIL добавить, то очень жаль. (с интероп — как сказали, все таки, накладные расходы).
.NET от этого только выиграл бы.
Re[5]: Можно ли делать вставки MSIL в код на c# ?
От: fddima  
Дата: 03.11.16 10:15
Оценка:
Здравствуйте, SergeyY, Вы писали:

SY>Про интероп понятно, спасибо.

Сам по себе интероп довольно быстр. Но ессно это оверкил для операций которые должны быть заинлайнены (навроде сложения, деления), но всё равно весьма и весьма прилично работает.
Есть ещё трюк с вызовом нативного кода не покидая managed context через делегаты/эмитинг msil — это ещё быстрее, но рекомендовать это не буду. Да я уже и не помню какой это выигрыш даст. Во времена дотнета 2.0 был ощутимый выигрыш, но и недостатков не меньше.
Re[3]: Можно ли делать вставки MSIL в код на c# ?
От: Sinix  
Дата: 03.11.16 10:17
Оценка: +1
Здравствуйте, SergeyY, Вы писали:

SY>Я не гоняюсь за сверх-оптимальностью, но здесь выигрыш был бы существенный..


Doing it wrong, без обид.

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

Не, если заморочиться, то можно получить довольно недорогой интероп, но не выгодней ли будет переташить в натив весь блок с вычислениями?
Re[4]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 10:23
Оценка:
Здравствуйте, Sinix, Вы писали:


S>Не, если заморочиться, то можно получить довольно недорогой интероп



Спасибо! интересно будет попробовать.
Re[3]: Можно ли делать вставки MSIL в код на c# ?
От: fddima  
Дата: 03.11.16 10:26
Оценка:
Здравствуйте, SergeyY, Вы писали:

SY>А если нельзя часть CIL добавить, то очень жаль. (с интероп — как сказали, все таки, накладные расходы).

Интероп можно и "похакать". Но поскольку у нас нативный код всё равно всё ещё где-то сбоку — просадки останутся. Под похакать я имею ввиду calli на нужный адрес. В принципе для кастомной арифметики могло бы подойти, но проблема в том что арифметика построеная таким образом незаинлайнится — и множество method-level оптимизаций останутся недоступными.

SY>.NET от этого только выиграл бы.

Врядли. Накой асм в дотнете? Так можно всё на асме написпл "вставками". Миксировать код никто не мешает и сейчас. Особенно если взять рантайм какойнибудь и похакать его, добавив интрисинков.

Для .NET — C++/CLI можно ещё попробовать для этого дела, но сам не люблю его. Предпочитаю классические плюсы отдельно, шарп отдельно.
Re[4]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 10:42
Оценка:
Здравствуйте, fddima, Вы писали:

F>Здравствуйте, SergeyY, Вы писали:


SY>>А если нельзя часть CIL добавить, то очень жаль. (с интероп — как сказали, все таки, накладные расходы).

F> Интероп можно и "похакать". Но поскольку у нас нативный код всё равно всё ещё где-то сбоку — просадки останутся. Под похакать я имею ввиду calli на нужный адрес. В принципе для кастомной арифметики могло бы подойти, но проблема в том что арифметика построеная таким образом незаинлайнится — и множество method-level оптимизаций останутся недоступными.

SY>>.NET от этого только выиграл бы.

F> Врядли. Накой асм в дотнете?

А чем было бы плохо, и сам .NET оптимизировать. Если была бы возможность что то дописывать в компилятор .NET, или сгенерировать какие то свои CIL инструкции.
Кому не нужно — тот в это не полезет. Кому интересно — открываются возможности.
Re[2]: Можно ли делать вставки MSIL в код на c# ?
От: Sharov Россия  
Дата: 03.11.16 10:45
Оценка: 24 (1) +1
Здравствуйте, Sinix, Вы писали:


S>Нормальной быстрой математики под дотнет нет, большинство реализаций ничего кроме фейспалма не вызывают. Как пример.


https://www.centerspace.net/nmath

Но там нет того, что нужно ТС.
Кодом людям нужно помогать!
Re[3]: Можно ли делать вставки MSIL в код на c# ?
От: Sinix  
Дата: 03.11.16 10:49
Оценка:
Здравствуйте, SergeyY, Вы писали:

SY>то я мог бы сделать библиотеку классов для работы с длинной арифметикой гораздо быстрее этих BigInteger-ов, и использовал бы все возможности 64-битных процессоров.

Нет никакого смысла — пришлось бы собирать и распространять копии под x86/x64/arm — раз, плюсы всё равно быстрее будут — два. Проще сразу в нативе это дело оформить.
Re: Можно ли делать вставки MSIL в код на c# ?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.11.16 10:59
Оценка:
Здравствуйте, SergeyY, Вы писали:

Тут для соседней темы искал нашел

https://ludeon.com/forums/index.php?topic=13813.0

 unsafe public sealed override void ResolveReferences()
        {
            Log.Warning("x86 override test 1");
            Log.Warning(TEST().ToString());

            byte* mpx_1 = (byte*)typeof(Redefine).GetMethod ("TEST", BindingFlags.Static | BindingFlags.Public).MethodHandle.GetFunctionPointer ().ToPointer();
            
            *(mpx_1 + 0) = 0xB8; //mov eax,0x0
            *(mpx_1 + 1) = 7;
            *(mpx_1 + 2) = 2;
            *(mpx_1 + 3) = 2;
            *(mpx_1 + 4) = 1;
            *(mpx_1 + 5) = 0xC3; //ret

            Log.Warning("x86 override test 2");
            Log.Warning(TEST().ToString());


            Log.Warning("have a nice day!");

            //StageA();
        }
и солнце б утром не вставало, когда бы не было меня
Re[5]: Можно ли делать вставки MSIL в код на c# ?
От: fddima  
Дата: 03.11.16 11:08
Оценка:
Здравствуйте, SergeyY, Вы писали:

SY>А чем было бы плохо, и сам .NET оптимизировать. Если была бы возможность что то дописывать в компилятор .NET, или сгенерировать какие то свои CIL инструкции.

Свои CIL инструкции в основном ненужны — интрисинки — обычные методы, но JIT — может быть осведомлен о них и генерировать соответствующий нативный код. Так было сделано в Mono.Simd, и так же в дотнете (вылетело из головы как оно у них там сейчас называется). Понятное дело, что легко это не расширяется, тем не менее при желании поднять свой форк моно или неткора — вполне реально. Но это очень дорого, в плане затрат — легче нарисовать, что нужно на C++.

SY>Кому не нужно — тот в это не полезет. Кому интересно — открываются возможности.

Вот оно приблизительно так сейчас и есть. В дотнете гораздо более актуальней просто более хороший JIT / и доступный для простых смертных .net native. Короче там и без этого вагон работы, а выигрыш от такой расширяемости неочевиден.
P/Invoke — же сам по себе использовать легко, модули вызывать свои можно без дополнительных приседаний. Там где нужно приседать — дотнет и так и так ложится плоховасто, по крайней мере пока.
Re[2]: Можно ли делать вставки MSIL в код на c# ?
От: SergeyY  
Дата: 03.11.16 11:32
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, SergeyY, Вы писали:


S>Тут для соседней темы искал нашел


S>https://ludeon.com/forums/index.php?topic=13813.0


S>
S> unsafe public sealed override void ResolveReferences()
S>        {
S>            Log.Warning("x86 override test 1");
S>            Log.Warning(TEST().ToString());

S>            byte* mpx_1 = (byte*)typeof(Redefine).GetMethod ("TEST", BindingFlags.Static | BindingFlags.Public).MethodHandle.GetFunctionPointer ().ToPointer();
            
S>            *(mpx_1 + 0) = 0xB8; //mov eax,0x0
S>            *(mpx_1 + 1) = 7;
S>            *(mpx_1 + 2) = 2;
S>            *(mpx_1 + 3) = 2;
S>            *(mpx_1 + 4) = 1;
S>            *(mpx_1 + 5) = 0xC3; //ret

S>            Log.Warning("x86 override test 2");
S>            Log.Warning(TEST().ToString());


S>            Log.Warning("have a nice day!");

S>            //StageA();
S>        }
S>



Спасибо, интересно. Это они переопределили метод, после копиляции в .NET ?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.