Assembler a .NET

Onestone

Assembler a .NET
« kdy: 07. 04. 2017, 23:22:10 »
Zdravím, mám aplikaci pro Linux, jejíž stěžejní část je v asm kvůli rychlosti (SIMD). Zákazník teď chce verzi pro Windows s GUI v .NET (resp. celou nevýpočetní částí v .NET). C# umím, abych udělal GUI, síťovou komunikaci apod., ale nevím, jak tam dostat ten kód v asm. Na zkoušku jsem zkusil stejný algoritmus v C# a je řádově pomalejší, takže ten asm má své opodstatnění. Existuje nějaká lepší možnost než udělat nativní DLL a pak použít P/Invoke? (Na Windows moc nedělám, a v .NET jen sporadicky, takže tady fakt nevím, co by bylo nejlepší, teď právě koukám na C++/CLI, jak to je schůdné.)


Lael.Ophir

Re:Assembler a .NET
« Odpověď #1 kdy: 08. 04. 2017, 00:35:52 »
Zdravím, mám aplikaci pro Linux, jejíž stěžejní část je v asm kvůli rychlosti (SIMD). Zákazník teď chce verzi pro Windows s GUI v .NET (resp. celou nevýpočetní částí v .NET). C# umím, abych udělal GUI, síťovou komunikaci apod., ale nevím, jak tam dostat ten kód v asm. Na zkoušku jsem zkusil stejný algoritmus v C# a je řádově pomalejší, takže ten asm má své opodstatnění. Existuje nějaká lepší možnost než udělat nativní DLL a pak použít P/Invoke? (Na Windows moc nedělám, a v .NET jen sporadicky, takže tady fakt nevím, co by bylo nejlepší, teď právě koukám na C++/CLI, jak to je schůdné.)

Nejlepší je asi oddělit ten ASM "backend" do samostatné knihovny, kterou pak můžete mít shodnou pro Linux i Windows. K tomu pak použijete odlišný UI projekt pro každou platformu. V .NETu použijete P/Invoke.
https://www.codeproject.com/Articles/1392/Using-Unmanaged-code-and-assembler-in-C

Alternativně můžete v C# zkusit SIMD-enabled vector types
https://msdn.microsoft.com/en-us/library/dn879696(v=vs.110).aspx

Další možnost je zkusit unsafe C#.
https://msdn.microsoft.com/en-us/library/aa288474.aspx

Pak jsou tu ještě exotičtější možnosti:
https://blogs.msdn.microsoft.com/devinj/2005/07/13/dynamically-writing-and-executing-native-assembly-in-c/
https://blogs.msdn.microsoft.com/jmstall/2005/02/21/tool-to-allow-inline-il-in-c-vb-net/

Vhodnost pro konkrétní použití bude nejspíš v pořadí, ve kterém jsem ty možnosti vypsal.

Martin Dráb

Re:Assembler a .NET
« Odpověď #2 kdy: 08. 04. 2017, 02:13:48 »
Doporučil bych jít cestou nativní DLL. Pokud ten kód napíšete rozumně, bude přenositelný i na Linux.

Co se týče SIMD a Assembleru, možná by vám stačilo použít jejich příslušné alternativy v C/C++. Tím se můžete Assembleru vyhnout docela, ale nebudete mít nad kódem takovou kontrolu. Příslušné hlavičkové soubory už by měly být stejná jak na Windows, tak na Linuxu (popř. shodné mezi GCC a MSVS), mrkněte na
http://stackoverflow.com/questions/11228855/header-files-for-x86-simd-intrinsics

Martin Dráb

Re:Assembler a .NET
« Odpověď #3 kdy: 08. 04. 2017, 02:15:25 »
C++/CLI nedoporučuji, pokud neotřebujete dělat složitější převody mezi oběma světy (.NET a nativním). Jestli si při předávání parametrů vystačíte s jednoducými typy, nemá podle mě C++/CLI smysl.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Assembler a .NET
« Odpověď #4 kdy: 08. 04. 2017, 11:21:36 »
Zdravím, mám aplikaci pro Linux, jejíž stěžejní část je v asm kvůli rychlosti (SIMD). Zákazník teď chce verzi pro Windows s GUI v .NET (resp. celou nevýpočetní částí v .NET). C# umím, abych udělal GUI, síťovou komunikaci apod., ale nevím, jak tam dostat ten kód v asm. Na zkoušku jsem zkusil stejný algoritmus v C# a je řádově pomalejší, takže ten asm má své opodstatnění. Existuje nějaká lepší možnost než udělat nativní DLL a pak použít P/Invoke? (Na Windows moc nedělám, a v .NET jen sporadicky, takže tady fakt nevím, co by bylo nejlepší, teď právě koukám na C++/CLI, jak to je schůdné.)
Nejlepší bude C++/CLI, umí předat pole přímo bez kopírování a pracovat s ním nativně (vytvoří se jen malý thunk). Je-li arr typu array<float>^, stačí pin_ptr<float> ptr = &arr[0]. Teď mám float*, který můžu použít v C a JSA a GC mi na něj nebude sahat (dealokovat/přesouvat). Pozor na překlad pro amd64, v takovém případě nelze použít inline assembler, bude to chtít masm. (Doporučuju dokumentaci Microsoftu k pin_ptr a interior_ptr.)


Jerry

Re:Assembler a .NET
« Odpověď #5 kdy: 08. 04. 2017, 15:40:52 »
...nepíšeš co konkrétního chceš převádět a to je duležité. Jaký je ten ranec interakcí GUI a back kodu v ASM. Jestli se něco 10 minut počítá a pak to něco vyplivne nebo jestli tam je interakce s GUI 10x za sekundu. Každý přechod z režimu unmanaged do managed ti sebere 4-6 instrukcí. To je hodně. Pokud je tam opravdu hodně x32/x64 ASM kodu tak mužeš použít Intel Parallel Studio ASM/C/C++ a napsat to v něm jako native x32/x64 kod a mužeš i využít akcelerací grafickou kartou a současně rozdělením procesu na více jader procesoru. To je ale opravdu hodně hodně náročná hračka. Záleží jak na tom jsi :) Taky mužeš využít nejnovější UWP C++/CX .NET Core 1.x jako native x32/x64 aplikaci bez GUI a GUI dopsat v UWP C# .NET Core 1.x. Ono klasické C# .NET x.xx je opravdu cca 4x pomalejší než native x32/x64 kod pokud je využívána GUI z .NET. Samotný výpočetní kod v C++/CLI bez interakce z GUI je cca stejně rychlý. UWP C++/CX .NET Core 1.x je rychlejší než staré C++/CLI .NET x.xx. Jinak C++/CLI je možné, ale musíš napsat řízený wrapper na obejktovou strukturu která je v native C++. Převádět jenom klasické C hodnoty je poněkud obskurní protože C++/CLI je čistě objektový, vše je v něm objektové, neexistuje tam něco jako DEFINE nebo globální proměnné apod. jako v Céčku. Pokud tvuj kod v ASM není objektový budeš muset nejprve napsat native objektový wrapper v C++ a pak teprve další objektový wrapper v C++/CLI - podle toho jak ten kod v ASM vypadá. Už jsi to někdy psal ???  Ono je to hodně náročné. ...

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Assembler a .NET
« Odpověď #6 kdy: 08. 04. 2017, 17:14:43 »
...nepíšeš co konkrétního chceš převádět a to je duležité. Jaký je ten ranec interakcí GUI a back kodu v ASM. Jestli se něco 10 minut počítá a pak to něco vyplivne nebo jestli tam je interakce s GUI 10x za sekundu. Každý přechod z režimu unmanaged do managed ti sebere 4-6 instrukcí. To je hodně. Pokud je tam opravdu hodně x32/x64 ASM kodu tak mužeš použít Intel Parallel Studio ASM/C/C++ a napsat to v něm jako native x32/x64 kod a mužeš i využít akcelerací grafickou kartou a současně rozdělením procesu na více jader procesoru. To je ale opravdu hodně hodně náročná hračka. Záleží jak na tom jsi :) Taky mužeš využít nejnovější UWP C++/CX .NET Core 1.x jako native x32/x64 aplikaci bez GUI a GUI dopsat v UWP C# .NET Core 1.x. Ono klasické C# .NET x.xx je opravdu cca 4x pomalejší než native x32/x64 kod pokud je využívána GUI z .NET. Samotný výpočetní kod v C++/CLI bez interakce z GUI je cca stejně rychlý. UWP C++/CX .NET Core 1.x je rychlejší než staré C++/CLI .NET x.xx. Jinak C++/CLI je možné, ale musíš napsat řízený wrapper na obejktovou strukturu která je v native C++. Převádět jenom klasické C hodnoty je poněkud obskurní protože C++/CLI je čistě objektový, vše je v něm objektové, neexistuje tam něco jako DEFINE nebo globální proměnné apod. jako v Céčku. Pokud tvuj kod v ASM není objektový budeš muset nejprve napsat native objektový wrapper v C++ a pak teprve další objektový wrapper v C++/CLI - podle toho jak ten kod v ASM vypadá. Už jsi to někdy psal ???  Ono je to hodně náročné. ...
Nesmysl, v C++/CLI stačí řízený wrapper přímo nad asm. Když už má asm pro Linux, jen upraví ABI a napíše nějakou ref class. Číselné typy jako int nebo float se nijak nepřevádí, z řízeného pole jde přímo získat void* pro asm. Krom již zmíněného pin_ptr to je přímočaré a bez overheadu. Jen se musí asm pro amd64 přeložit zvlášť (pro 32bit stačí inline, ale to už snad nikdo nepoužívá).

mrazik

Re:Assembler a .NET
« Odpověď #7 kdy: 08. 04. 2017, 17:19:05 »
Citace
... mám aplikaci pro Linux, jejíž stěžejní část je v asm kvůli rychlosti (SIMD)...
Poměrně důležitá je v tomto případě i informace, zda je použita syntaxe AT&T nebo Intel. V Linuxu se běžně používá AT&T, gcc si však poradí i se syntaxí Intel, otázka je zda si nástroje Microsoftu poradí s AT&T. A pokud vytvoříte dll pomocí gcc do jaké míry je to kompatibilní na úrovni ABI (tady jak se předávají parametry) s .NET. Moc neporadím, protože s .NET nekamarádím, ale pokud je to opravdu v AT&T, tak to zas taková sranda asi nebude.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Assembler a .NET
« Odpověď #8 kdy: 08. 04. 2017, 17:25:35 »
Citace
... mám aplikaci pro Linux, jejíž stěžejní část je v asm kvůli rychlosti (SIMD)...
Poměrně důležitá je v tomto případě i informace, zda je použita syntaxe AT&T nebo Intel. V Linuxu se běžně používá AT&T, gcc si však poradí i se syntaxí Intel, otázka je zda si nástroje Microsoftu poradí s AT&T. A pokud vytvoříte dll pomocí gcc do jaké míry je to kompatibilní na úrovni ABI (tady jak se předávají parametry) s .NET. Moc neporadím, protože s .NET nekamarádím, ale pokud je to opravdu v AT&T, tak to zas taková sranda asi nebude.
S gcc jde vytvořit statická knihovna a z toho pak dll se správným ABI. Nicméně k překladu asm je lepší použít přímo VS, nativní dll je v tomto případě k ničemu, bude-li se ten kód se SIMD používat jen z .NET.

borekz

  • ****
  • 493
    • Zobrazit profil
    • E-mail
Re:Assembler a .NET
« Odpověď #9 kdy: 08. 04. 2017, 18:02:12 »
Pokud by pinvoke bylo úzké hrdlo, tady je ukázka, jak jde binární kód spouštět přímo v CLR: https://www.codeproject.com/tips/855149/csharp-fast-memory-copy-method-with-x-assembly-usa

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Assembler a .NET
« Odpověď #10 kdy: 09. 04. 2017, 11:25:21 »
Pokud by pinvoke bylo úzké hrdlo, tady je ukázka, jak jde binární kód spouštět přímo v CLR: https://www.codeproject.com/tips/855149/csharp-fast-memory-copy-method-with-x-assembly-usa
Tento způsob by nikdo příčetný nepoužil.