SlideShare une entreprise Scribd logo
1  sur  55
Télécharger pour lire hors ligne
FFI              História, performance e
                            felicidade com Ruby



                            Vitor Capela
domingo, 3 de março de 13
@dodecaphonic


domingo, 3 de março de 13

Sou @dodecaphonic no Twitter. Fico com essa cara quando o computador não faz o que eu
mando.
Meu trabalho às vezes exige que eu transforme isto...




domingo, 3 de março de 13

Eu trabalho com geoprocessamento. Isso envolve tanto fazer coisas babacas com Google
Maps como transformar uma nuvem de pontos de um levantamento a laser...
... nisto.




domingo, 3 de março de 13

... em uma malha de triângulos. Essa malha pode ser um terreno em que algo vai ser
construído, pode ser o levantamento do relevo para um estudo hidrológico, pode ser um
scan para modelagem de um projeto de reconstrução.
A gente ama Ruby.
      O Ruby ama a gente também.
                                                      ❤
domingo, 3 de março de 13

E eu gosto de fazer isso com Ruby. É muito gratificante dar uma solução sucinta, ou então
bem flexível, a problemas que em linguagens tradicionais do mercado seriam enfadonhos. Há
oito anos ele é meu canivete suíço.
A gente ama Ruby.
      O Ruby ama a gente também.
                                                      ❤
domingo, 3 de março de 13

E eu gosto de fazer isso com Ruby. É muito gratificante dar uma solução sucinta, ou então
bem flexível, a problemas que em linguagens tradicionais do mercado seriam enfadonhos. Há
oito anos ele é meu canivete suíço.
Mas às vezes o amor não resolve.




domingo, 3 de março de 13

Sendo muito honesto, no entanto, nem sempre é a solução ideal.
Vamos combinar, gente: tem vezes que o
  Ruby não é rápido o bastante.




domingo, 3 de março de 13

Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você
precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de
soluções que tomem o mínimo possível de tempo.
Vamos combinar, gente: tem vezes que o
  Ruby não é rápido o bastante.

   “Não é verdade: você precisa apenas de algoritmos melhores!”




domingo, 3 de março de 13

Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você
precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de
soluções que tomem o mínimo possível de tempo.
Vamos combinar, gente: tem vezes que o
  Ruby não é rápido o bastante.

   “Não é verdade: você precisa apenas de algoritmos melhores!”



  “Quem se importa? 99% dos problemas se resumem a IO.”




domingo, 3 de março de 13

Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você
precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de
soluções que tomem o mínimo possível de tempo.
Vamos combinar, gente: tem vezes que o
  Ruby não é rápido o bastante.

   “Não é verdade: você precisa apenas de algoritmos melhores!”
                                                        E se eu já tiver tentado ?

  “Quem se importa? 99% dos problemas se resumem a IO.”




domingo, 3 de março de 13

Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você
precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de
soluções que tomem o mínimo possível de tempo.
Vamos combinar, gente: tem vezes que o
  Ruby não é rápido o bastante.

   “Não é verdade: você precisa apenas de algoritmos melhores!”
                                                        E se eu já tiver tentado ?

  “Quem se importa? 99% dos problemas se resumem a IO.”
                                                        Pois é: 99%, não 100%.



domingo, 3 de março de 13

Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você
precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de
soluções que tomem o mínimo possível de tempo.
“Então vá programar em <Python|
                   Java|Scala|Clojure|Haskell...>!”



domingo, 3 de março de 13

Já ouvi e já disse para mim mesmo algumas vezes: vá para outras linguagens. E já fui: resolvo
e resolvi coisas com C++, aplico Scala aqui e ali, faço o que for preciso se o Ruby não der
conta.
EU AMO o Ruby.
     A gente ama
     O Ruby ama a MIM também.
                  gente
                                                      ❤
domingo, 3 de março de 13

Mas isso não muda o fato de que quero usá-lo sempre que possível.
EU AMO o Ruby.
     A gente ama
     O Ruby ama a MIM também.
                  gente
                                                      ❤
domingo, 3 de março de 13

Mas isso não muda o fato de que quero usá-lo sempre que possível.
Se eu quero me manter programando
              em Ruby sem comprometer as
              necessidades dos meus projetos, a
              solução é apelar para o C*.

              * Depois de tentar o JRuby, claro.


domingo, 3 de março de 13

Com isso em mente, sempre que um problema aperta eu tento primeiro ir para o JRuby (com
invokedynamic ligado); se ainda assim não for o bastante, meu (nosso) melhor amigo ainda é
o C.
RUBY & C
domingo, 3 de março de 13
A gente ainda estava aprendendo o
           beabá e o C já resolvia problemas muito
           complicados.


domingo, 3 de março de 13

Às vezes a gente tem a impressão de que o mundo começou quando passamos a dar atenção
a ele. Que todos os nossos problemas são novos ou únicos de alguma maneira. Os barbudos
nos laboratórios escuros espalhados pelo mundo inventaram a Internet e o Unix enquanto a
gente nem pensava em nascer.
Isso significa que há bibliotecas às
           pencas, várias extremamente maduras e
           mantidas há décadas.


domingo, 3 de março de 13

O legado (o BOM legado) é imenso.
Ainda não há uma gem para resolver
           qualquer parada.



domingo, 3 de março de 13

Por mais que milhares de gems pipoquem a cada mês, não há solução para tudo. Encontro
isso todos os dias no meu trabalho.
ruby-ffi é o menor caminho entre seu
          programa Ruby e alguma biblioteca
          supimpa (e rápida!) que já esteja por aí.


domingo, 3 de março de 13

E para aproveitar esse legado, a melhor coisa atualmente é usar o ruby-ffi.
FOREIGN
          FUNCTION
          INTERFACE
                                            Java                     JNI
                                            .NET                     P/Invoke
                                            Python                   ctypes
                                            Mobile JS                PhoneGap

domingo, 3 de março de 13

O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de
ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
FOREIGN
          FUNCTION
          INTERFACE
                                            Java                     JNI
                                            .NET                     P/Invoke
                                            Python                   ctypes
                                            Mobile JS                PhoneGap
                                            Ruby
domingo, 3 de março de 13

O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de
ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
FOREIGN
          FUNCTION
          INTERFACE
                                            Java                     JNI
                                            .NET                     P/Invoke
                                            Python                   ctypes
                                            Mobile JS                PhoneGap
                                            Ruby
domingo, 3 de março de 13

O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de
ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
FOREIGN
          FUNCTION
          INTERFACE
                                            Java                     JNI
                                            .NET                     P/Invoke
                                            Python                   ctypes
                                            Mobile JS                PhoneGap
                                            Ruby                     ruby-ffi
domingo, 3 de março de 13

O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de
ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
Uma FFI permite que você chame funções
           em uma outra linguagem.



domingo, 3 de março de 13
“Mas qual é a diferença de escrever uma
         extensão em C?”



domingo, 3 de março de 13
domingo, 3 de março de 13

Não é preciso saber programar em C, ou TER que programar em C, para poder usar uma
biblioteca. Isso significa também que você não precisa compilar nada (o que é especialmente
bom no Windows).
Você só precisa escrever Ruby.




domingo, 3 de março de 13

Não é preciso saber programar em C, ou TER que programar em C, para poder usar uma
biblioteca. Isso significa também que você não precisa compilar nada (o que é especialmente
bom no Windows).
Você não precisa de headers ou da
            versão de desenvolvimento da
            biblioteca para distribuir sua gem.


domingo, 3 de março de 13
Você pode usar o resultado em
             qualquer Ruby (MRI, JRuby, Rubinius,
             Maglev, ...) sem nenhuma modificação
             ou restrição.


domingo, 3 de março de 13

Seu resultado não fica restrito ao MRI, nem sujeito às idiossincrasias das camadas de
adaptação de extensões C que o JRuby e Rubinius oferecem.
Você não corre o risco da sua gem
            quebrar quando/se mudar a API de
            extensão do MRI.


domingo, 3 de março de 13
É muito fácil de usar.




domingo, 3 de março de 13
MESHERATOR
domingo, 3 de março de 13

Para ilustrar o ganho que uma biblioteca em C pode trazer a um projeto, escrevi um pequeno
demo. “MESHERATOR” - MESH GENERATOR, um gerador de malhas trianguladas. Muito
criativo.
Transformar isto...




domingo, 3 de março de 13

E se vocês se lembram do começo da apresentação, meu objetivo era sair disto...
... nisto.




domingo, 3 de março de 13

... para isto.
Este cara sabe como triangular
                            nuvens de pontos muito
                            rapidamente.


                              JONATHAN
                              SHEWCHUCK
                            Sua biblioteca, por não ser em
                            Ruby, não tem um nome criativo
                            ou engraçadinho: é TRIANGLE,
                            mesmo.

domingo, 3 de março de 13
DEMO
domingo, 3 de março de 13
A API é bem pequena.
       void triangulate(char *, struct triangulateio *, struct triangulateio *,
                        struct triangulateio *);
       void trifree(VOID *memptr);




                Uma string com as opções.       A estrutura de entrada e saída do algoritmo.




domingo, 3 de março de 13

Não há muito a encapsular para usar essa biblioteca. char* em C é uma string. triangulateio é
uma estrutura de dados. * é um ponteiro. “triangulate” transforma a nuvem de pontos em
triângulos; “trifree” permite que eu libere a memória alocada pelo algoritmo.
struct triangulateio {
             REAL *pointlist;                                                  /*   In   /   out   */
             REAL *pointattributelist;                                         /*   In   /   out   */
             int *pointmarkerlist;                                             /*   In   /   out   */
             int numberofpoints;                                               /*   In   /   out   */
             int numberofpointattributes;                                      /*   In   /   out   */

               int *trianglelist;                                              /* In / out         */
               REAL *triangleattributelist;                                    /* In / out         */
               REAL *trianglearealist;                                          /* In only         */
               int *neighborlist;                                              /* Out only         */
                                         triangle.c:19 - #define REAL double
               int numberoftriangles;                                          /* In / out         */
               int numberofcorners;                                            /* In / out         */
               int numberoftriangleattributes;                                 /* In / out         */

               int *segmentlist;                                               /* In / out */
               int *segmentmarkerlist;                                         /* In / out */
               int numberofsegments;                                           /* In / out */

               REAL *holelist;                        /* In / pointer to array copied out */
               int numberofholes;                                      /* In / copied out */

               REAL *regionlist;                      /* In / pointer to array copied out */
               int numberofregions;                                    /* In / copied out */

              int *edgelist;                                                  /*    Out   only     */
              int *edgemarkerlist;             /* Not used with Voronoi diagram;    out   only     */
              REAL *normlist;                 /* Used only with Voronoi diagram;    out   only     */
              int numberofedges;                                              /*    Out   only     */
            };

domingo, 3 de março de 13

A estrutura é bem compreensível e descritiva (supondo que você conheça o domínio). Os
tipos de dados também. A única coisa pouco familiar é “REAL” — que, olhando no código, é
apenas um double.
Vamos começar definindo nosso
            encapsulamento com FFI.



domingo, 3 de março de 13
require 'ffi'

       module Mesherator
         module TriangleFFI
           extend FFI::Library
           ffi_lib 'libtriangle'

                typedef :pointer, :triangulateio

           attach_function :triangulate,
       [:string, :triangulateio, :triangulateio, :triangulateio], :void
           attach_function :trifree, [:pointer], :void
         end
       end




domingo, 3 de março de 13

Aqui defino então as duas funções. “attach_function” procura uma função de mesmo nome
na biblioteca definida em “ffi_lib”. Os valores no array são os tipos de dados que a funcão
recebe; o último argumento é o retorno. Como ambas não retornam nada (operam
diretamente em ponteiros passados para elas), declaro como :void.
Uma struct básica é mapeada com
                   FFI::Struct.



domingo, 3 de março de 13
class TriangulateIO < ::FFI::Struct
           layout :pointlist, :pointer,
                  :pointattributelist, :pointer,
                  :pointmarkerlist, :pointer,
                                                    Todo ponteiro (*) vira :pointer
                  :numberofpoints, :int,
                  :numberofpointattributes, :int,
                  :trianglelist, :pointer,
                  :triangleattributelist, :pointer,
                  :trianglearealist, :pointer,
                  :neighborlist, :pointer,
                  :numberoftriangles, :int,
                  :numberofcorners, :int,
                  :numberoftriangleattributes, :int,
                  :segmentlist, :pointer,
                  :segmentmarkerlist, :pointer,
                  :numberofsegments, :int,
                  :holelist, :pointer,
                  :numberofholes, :int,
                  :regionlist, :pointer,
                  :numberofregions, :int,
                  :edgelist, :pointer,
                  :edgemarkerlist, :pointer,
                  :normlist, :pointer,
                  :numberofedges, :int
         end

domingo, 3 de março de 13

Então eis a estrutura análoga em Ruby. Mantive os mesmos nomes, exatamente, para facilitar
o entendimento, mas não é obrigatório: o mais importante é manter a ordem dos tipos de
dados.
layout garante que o bloco de memória
        criado em C se encaixará como uma luva.



domingo, 3 de março de 13

Se a ordem e os tipos forem mantidos, isso significa que quando eu falar em “pointlist” no
Ruby, estarei acessando o pedacinho de memória que se refere a “pointlist” no C.
E agora, uma classe em Ruby
         arrematando a parada toda.



domingo, 3 de março de 13
class DelaunayTriangulator
             attr_reader :points

               def initialize(points)
                 @points = points
               end

             def triangulate
               point_array_ptr = FFI::MemoryPointer.new(:double,
           points.size * 2)
               point_array_ptr.write_array_of_double(flatten(points))

                   input = TriangulateIO.new
                   output = TriangulateIO.new

                   input[:pointlist] = point_array_ptr
                   input[:numberofpoints] = points.size
                   input[:numberofpointattributes] = 0

                   TriangleFFI.triangulate 'czeXQ', input, output, nil

                 read_triangles_from output
               ensure
                 free input
                 free output
               end

             # ...
           end


domingo, 3 de março de 13
# ...
   point_array_ptr = FFI::MemoryPointer.new(:double, points.size * 2)
   point_array_ptr.write_array_of_double(flatten(points))

    # ...
    input[:pointlist] = point_array_ptr
    input[:numberofpoints] = points.size
    input[:numberofpointattributes] = 0

    # ...
                                Libera toda memória alocada em Ruby no próximo ciclo de
                                    GC, a não ser que você especifique algo diferente.




domingo, 3 de março de 13

Aqui acontece a única parte bem FFI mesmo: eu tenho que alocar um ponteiro que receberá
meu array de pontos para passar ao C, e preciso colocar isso no meu TriangulateIO em
“input”.
# ...
          ensure
           free input                           Como há memória alocada no
           free output                            C, eu tenho que liberá-la.
          end




domingo, 3 de março de 13

Como a biblioteca estipula que eu tenho que liberar toda a memória que o algoritmo por
ventura alocar, adiciono um bloco ensure no final que chama DelaunayTriangulator#free em
ambas as structs e cuida disso. Existe outra técnica (via ManagedStruct) que eliminaria esta
seção.
def read_triangles_from(triangulateio)
            triangle_count   = triangulateio[:numberoftriangles]
            triangle_indices =
         triangulateio[:trianglelist].read_array_of_int(triangle_count * 3)

               triangles = []

               0.step(triangle_indices.size - 1, 3) do |first_point_index|
                 p0 = points[triangle_indices[first_point_index]]
                 p1 = points[triangle_indices[first_point_index + 1]]
                 p2 = points[triangle_indices[first_point_index + 2]]
                 triangles << Triangle.new(p0, p1, p2)
               end

            triangles
         end




domingo, 3 de março de 13

Aqui transformo os triângulos em “output” em instâncias de Triangle dentro do meu domínio.
“trianglelist” é uma lista de índices apontado para o array original de pontos.
Não dói muito, e você só precisa saber
             um tiquinho de C.



domingo, 3 de março de 13

É tranquilo. Você precisa saber o que é um ponteiro e que cada biblioteca tem alguma
particularidade no gerenciamento de memória (apesar de, no C, haver um quase consenso de
que quem usa uma biblioteca aloca e libera os buffers necessários/criados).
DEMO
domingo, 3 de março de 13
@dodecaphonic


domingo, 3 de março de 13

É isso. Obrigado pela atenção, e espero que tenha sido útil de alguma maneira.
PERGUNTAS
domingo, 3 de março de 13
http://github.com/dodecaphonic/mesherator
         http://www.cs.cmu.edu/~quake/triangle.html

                  http://en.wikipedia.org/wiki/Delaunay_triangulation




domingo, 3 de março de 13

Contenu connexe

En vedette

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

En vedette (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

FFI - História, performance e felicidade com Ruby

  • 1. FFI História, performance e felicidade com Ruby Vitor Capela domingo, 3 de março de 13
  • 2. @dodecaphonic domingo, 3 de março de 13 Sou @dodecaphonic no Twitter. Fico com essa cara quando o computador não faz o que eu mando.
  • 3. Meu trabalho às vezes exige que eu transforme isto... domingo, 3 de março de 13 Eu trabalho com geoprocessamento. Isso envolve tanto fazer coisas babacas com Google Maps como transformar uma nuvem de pontos de um levantamento a laser...
  • 4. ... nisto. domingo, 3 de março de 13 ... em uma malha de triângulos. Essa malha pode ser um terreno em que algo vai ser construído, pode ser o levantamento do relevo para um estudo hidrológico, pode ser um scan para modelagem de um projeto de reconstrução.
  • 5. A gente ama Ruby. O Ruby ama a gente também. ❤ domingo, 3 de março de 13 E eu gosto de fazer isso com Ruby. É muito gratificante dar uma solução sucinta, ou então bem flexível, a problemas que em linguagens tradicionais do mercado seriam enfadonhos. Há oito anos ele é meu canivete suíço.
  • 6. A gente ama Ruby. O Ruby ama a gente também. ❤ domingo, 3 de março de 13 E eu gosto de fazer isso com Ruby. É muito gratificante dar uma solução sucinta, ou então bem flexível, a problemas que em linguagens tradicionais do mercado seriam enfadonhos. Há oito anos ele é meu canivete suíço.
  • 7. Mas às vezes o amor não resolve. domingo, 3 de março de 13 Sendo muito honesto, no entanto, nem sempre é a solução ideal.
  • 8. Vamos combinar, gente: tem vezes que o Ruby não é rápido o bastante. domingo, 3 de março de 13 Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de soluções que tomem o mínimo possível de tempo.
  • 9. Vamos combinar, gente: tem vezes que o Ruby não é rápido o bastante. “Não é verdade: você precisa apenas de algoritmos melhores!” domingo, 3 de março de 13 Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de soluções que tomem o mínimo possível de tempo.
  • 10. Vamos combinar, gente: tem vezes que o Ruby não é rápido o bastante. “Não é verdade: você precisa apenas de algoritmos melhores!” “Quem se importa? 99% dos problemas se resumem a IO.” domingo, 3 de março de 13 Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de soluções que tomem o mínimo possível de tempo.
  • 11. Vamos combinar, gente: tem vezes que o Ruby não é rápido o bastante. “Não é verdade: você precisa apenas de algoritmos melhores!” E se eu já tiver tentado ? “Quem se importa? 99% dos problemas se resumem a IO.” domingo, 3 de março de 13 Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de soluções que tomem o mínimo possível de tempo.
  • 12. Vamos combinar, gente: tem vezes que o Ruby não é rápido o bastante. “Não é verdade: você precisa apenas de algoritmos melhores!” E se eu já tiver tentado ? “Quem se importa? 99% dos problemas se resumem a IO.” Pois é: 99%, não 100%. domingo, 3 de março de 13 Às vezes seus problemas recaem justamente sobre os pontos fracos da linguagem: você precisa de previsibilidade nas alocações de memória, de altíssimo desempenho numérico, de soluções que tomem o mínimo possível de tempo.
  • 13. “Então vá programar em <Python| Java|Scala|Clojure|Haskell...>!” domingo, 3 de março de 13 Já ouvi e já disse para mim mesmo algumas vezes: vá para outras linguagens. E já fui: resolvo e resolvi coisas com C++, aplico Scala aqui e ali, faço o que for preciso se o Ruby não der conta.
  • 14. EU AMO o Ruby. A gente ama O Ruby ama a MIM também. gente ❤ domingo, 3 de março de 13 Mas isso não muda o fato de que quero usá-lo sempre que possível.
  • 15. EU AMO o Ruby. A gente ama O Ruby ama a MIM também. gente ❤ domingo, 3 de março de 13 Mas isso não muda o fato de que quero usá-lo sempre que possível.
  • 16. Se eu quero me manter programando em Ruby sem comprometer as necessidades dos meus projetos, a solução é apelar para o C*. * Depois de tentar o JRuby, claro. domingo, 3 de março de 13 Com isso em mente, sempre que um problema aperta eu tento primeiro ir para o JRuby (com invokedynamic ligado); se ainda assim não for o bastante, meu (nosso) melhor amigo ainda é o C.
  • 17. RUBY & C domingo, 3 de março de 13
  • 18. A gente ainda estava aprendendo o beabá e o C já resolvia problemas muito complicados. domingo, 3 de março de 13 Às vezes a gente tem a impressão de que o mundo começou quando passamos a dar atenção a ele. Que todos os nossos problemas são novos ou únicos de alguma maneira. Os barbudos nos laboratórios escuros espalhados pelo mundo inventaram a Internet e o Unix enquanto a gente nem pensava em nascer.
  • 19. Isso significa que há bibliotecas às pencas, várias extremamente maduras e mantidas há décadas. domingo, 3 de março de 13 O legado (o BOM legado) é imenso.
  • 20. Ainda não há uma gem para resolver qualquer parada. domingo, 3 de março de 13 Por mais que milhares de gems pipoquem a cada mês, não há solução para tudo. Encontro isso todos os dias no meu trabalho.
  • 21. ruby-ffi é o menor caminho entre seu programa Ruby e alguma biblioteca supimpa (e rápida!) que já esteja por aí. domingo, 3 de março de 13 E para aproveitar esse legado, a melhor coisa atualmente é usar o ruby-ffi.
  • 22. FOREIGN FUNCTION INTERFACE Java JNI .NET P/Invoke Python ctypes Mobile JS PhoneGap domingo, 3 de março de 13 O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
  • 23. FOREIGN FUNCTION INTERFACE Java JNI .NET P/Invoke Python ctypes Mobile JS PhoneGap Ruby domingo, 3 de março de 13 O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
  • 24. FOREIGN FUNCTION INTERFACE Java JNI .NET P/Invoke Python ctypes Mobile JS PhoneGap Ruby domingo, 3 de março de 13 O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
  • 25. FOREIGN FUNCTION INTERFACE Java JNI .NET P/Invoke Python ctypes Mobile JS PhoneGap Ruby ruby-ffi domingo, 3 de março de 13 O que é uma FFI, afinal? Já falei disso algumas vezes sem dar uma definição. FFI é um jeito de ligar duas linguagens díspares de modo que uma possa fazer uso da outra.
  • 26. Uma FFI permite que você chame funções em uma outra linguagem. domingo, 3 de março de 13
  • 27. “Mas qual é a diferença de escrever uma extensão em C?” domingo, 3 de março de 13
  • 28. domingo, 3 de março de 13 Não é preciso saber programar em C, ou TER que programar em C, para poder usar uma biblioteca. Isso significa também que você não precisa compilar nada (o que é especialmente bom no Windows).
  • 29. Você só precisa escrever Ruby. domingo, 3 de março de 13 Não é preciso saber programar em C, ou TER que programar em C, para poder usar uma biblioteca. Isso significa também que você não precisa compilar nada (o que é especialmente bom no Windows).
  • 30. Você não precisa de headers ou da versão de desenvolvimento da biblioteca para distribuir sua gem. domingo, 3 de março de 13
  • 31. Você pode usar o resultado em qualquer Ruby (MRI, JRuby, Rubinius, Maglev, ...) sem nenhuma modificação ou restrição. domingo, 3 de março de 13 Seu resultado não fica restrito ao MRI, nem sujeito às idiossincrasias das camadas de adaptação de extensões C que o JRuby e Rubinius oferecem.
  • 32. Você não corre o risco da sua gem quebrar quando/se mudar a API de extensão do MRI. domingo, 3 de março de 13
  • 33. É muito fácil de usar. domingo, 3 de março de 13
  • 34. MESHERATOR domingo, 3 de março de 13 Para ilustrar o ganho que uma biblioteca em C pode trazer a um projeto, escrevi um pequeno demo. “MESHERATOR” - MESH GENERATOR, um gerador de malhas trianguladas. Muito criativo.
  • 35. Transformar isto... domingo, 3 de março de 13 E se vocês se lembram do começo da apresentação, meu objetivo era sair disto...
  • 36. ... nisto. domingo, 3 de março de 13 ... para isto.
  • 37. Este cara sabe como triangular nuvens de pontos muito rapidamente. JONATHAN SHEWCHUCK Sua biblioteca, por não ser em Ruby, não tem um nome criativo ou engraçadinho: é TRIANGLE, mesmo. domingo, 3 de março de 13
  • 38. DEMO domingo, 3 de março de 13
  • 39. A API é bem pequena. void triangulate(char *, struct triangulateio *, struct triangulateio *, struct triangulateio *); void trifree(VOID *memptr); Uma string com as opções. A estrutura de entrada e saída do algoritmo. domingo, 3 de março de 13 Não há muito a encapsular para usar essa biblioteca. char* em C é uma string. triangulateio é uma estrutura de dados. * é um ponteiro. “triangulate” transforma a nuvem de pontos em triângulos; “trifree” permite que eu libere a memória alocada pelo algoritmo.
  • 40. struct triangulateio { REAL *pointlist; /* In / out */ REAL *pointattributelist; /* In / out */ int *pointmarkerlist; /* In / out */ int numberofpoints; /* In / out */ int numberofpointattributes; /* In / out */ int *trianglelist; /* In / out */ REAL *triangleattributelist; /* In / out */ REAL *trianglearealist; /* In only */ int *neighborlist; /* Out only */ triangle.c:19 - #define REAL double int numberoftriangles; /* In / out */ int numberofcorners; /* In / out */ int numberoftriangleattributes; /* In / out */ int *segmentlist; /* In / out */ int *segmentmarkerlist; /* In / out */ int numberofsegments; /* In / out */ REAL *holelist; /* In / pointer to array copied out */ int numberofholes; /* In / copied out */ REAL *regionlist; /* In / pointer to array copied out */ int numberofregions; /* In / copied out */ int *edgelist; /* Out only */ int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ REAL *normlist; /* Used only with Voronoi diagram; out only */ int numberofedges; /* Out only */ }; domingo, 3 de março de 13 A estrutura é bem compreensível e descritiva (supondo que você conheça o domínio). Os tipos de dados também. A única coisa pouco familiar é “REAL” — que, olhando no código, é apenas um double.
  • 41. Vamos começar definindo nosso encapsulamento com FFI. domingo, 3 de março de 13
  • 42. require 'ffi' module Mesherator module TriangleFFI extend FFI::Library ffi_lib 'libtriangle' typedef :pointer, :triangulateio attach_function :triangulate, [:string, :triangulateio, :triangulateio, :triangulateio], :void attach_function :trifree, [:pointer], :void end end domingo, 3 de março de 13 Aqui defino então as duas funções. “attach_function” procura uma função de mesmo nome na biblioteca definida em “ffi_lib”. Os valores no array são os tipos de dados que a funcão recebe; o último argumento é o retorno. Como ambas não retornam nada (operam diretamente em ponteiros passados para elas), declaro como :void.
  • 43. Uma struct básica é mapeada com FFI::Struct. domingo, 3 de março de 13
  • 44. class TriangulateIO < ::FFI::Struct layout :pointlist, :pointer, :pointattributelist, :pointer, :pointmarkerlist, :pointer, Todo ponteiro (*) vira :pointer :numberofpoints, :int, :numberofpointattributes, :int, :trianglelist, :pointer, :triangleattributelist, :pointer, :trianglearealist, :pointer, :neighborlist, :pointer, :numberoftriangles, :int, :numberofcorners, :int, :numberoftriangleattributes, :int, :segmentlist, :pointer, :segmentmarkerlist, :pointer, :numberofsegments, :int, :holelist, :pointer, :numberofholes, :int, :regionlist, :pointer, :numberofregions, :int, :edgelist, :pointer, :edgemarkerlist, :pointer, :normlist, :pointer, :numberofedges, :int end domingo, 3 de março de 13 Então eis a estrutura análoga em Ruby. Mantive os mesmos nomes, exatamente, para facilitar o entendimento, mas não é obrigatório: o mais importante é manter a ordem dos tipos de dados.
  • 45. layout garante que o bloco de memória criado em C se encaixará como uma luva. domingo, 3 de março de 13 Se a ordem e os tipos forem mantidos, isso significa que quando eu falar em “pointlist” no Ruby, estarei acessando o pedacinho de memória que se refere a “pointlist” no C.
  • 46. E agora, uma classe em Ruby arrematando a parada toda. domingo, 3 de março de 13
  • 47. class DelaunayTriangulator attr_reader :points def initialize(points) @points = points end def triangulate point_array_ptr = FFI::MemoryPointer.new(:double, points.size * 2) point_array_ptr.write_array_of_double(flatten(points)) input = TriangulateIO.new output = TriangulateIO.new input[:pointlist] = point_array_ptr input[:numberofpoints] = points.size input[:numberofpointattributes] = 0 TriangleFFI.triangulate 'czeXQ', input, output, nil read_triangles_from output ensure free input free output end # ... end domingo, 3 de março de 13
  • 48. # ... point_array_ptr = FFI::MemoryPointer.new(:double, points.size * 2) point_array_ptr.write_array_of_double(flatten(points)) # ... input[:pointlist] = point_array_ptr input[:numberofpoints] = points.size input[:numberofpointattributes] = 0 # ... Libera toda memória alocada em Ruby no próximo ciclo de GC, a não ser que você especifique algo diferente. domingo, 3 de março de 13 Aqui acontece a única parte bem FFI mesmo: eu tenho que alocar um ponteiro que receberá meu array de pontos para passar ao C, e preciso colocar isso no meu TriangulateIO em “input”.
  • 49. # ... ensure free input Como há memória alocada no free output C, eu tenho que liberá-la. end domingo, 3 de março de 13 Como a biblioteca estipula que eu tenho que liberar toda a memória que o algoritmo por ventura alocar, adiciono um bloco ensure no final que chama DelaunayTriangulator#free em ambas as structs e cuida disso. Existe outra técnica (via ManagedStruct) que eliminaria esta seção.
  • 50. def read_triangles_from(triangulateio) triangle_count = triangulateio[:numberoftriangles] triangle_indices = triangulateio[:trianglelist].read_array_of_int(triangle_count * 3) triangles = [] 0.step(triangle_indices.size - 1, 3) do |first_point_index| p0 = points[triangle_indices[first_point_index]] p1 = points[triangle_indices[first_point_index + 1]] p2 = points[triangle_indices[first_point_index + 2]] triangles << Triangle.new(p0, p1, p2) end triangles end domingo, 3 de março de 13 Aqui transformo os triângulos em “output” em instâncias de Triangle dentro do meu domínio. “trianglelist” é uma lista de índices apontado para o array original de pontos.
  • 51. Não dói muito, e você só precisa saber um tiquinho de C. domingo, 3 de março de 13 É tranquilo. Você precisa saber o que é um ponteiro e que cada biblioteca tem alguma particularidade no gerenciamento de memória (apesar de, no C, haver um quase consenso de que quem usa uma biblioteca aloca e libera os buffers necessários/criados).
  • 52. DEMO domingo, 3 de março de 13
  • 53. @dodecaphonic domingo, 3 de março de 13 É isso. Obrigado pela atenção, e espero que tenha sido útil de alguma maneira.
  • 54. PERGUNTAS domingo, 3 de março de 13
  • 55. http://github.com/dodecaphonic/mesherator http://www.cs.cmu.edu/~quake/triangle.html http://en.wikipedia.org/wiki/Delaunay_triangulation domingo, 3 de março de 13