Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fazendo o compilador trabalhar por você: técnicas de manipulação e otimização de código

Fazendo o compilador trabalhar por você: técnicas de manipulação e otimização de código

Slides da apresentação para o QCon Hub: https://www.infoq.com/br/presentations/tecnicas-de-manipulacao-e-otimizacao-de-codigo/

Otimização de código é fundamental no software moderno, transformando o código que escrevemos para representar o negócio em algo que o hardware possa entender e executar de forma eficiente. Nesta sessão você aprenderá sobre como a compilação do código pode ser manipulada. Tendo como exemplo o Quill, você verá como a informação por trás do seu código é lida, interpretada e otimizada.

Juliano Alves

December 28, 2020
Tweet

More Decks by Juliano Alves

Other Decks in Technology

Transcript

  1. Fazendo o compilador trabalhar por você: técnicas de manipulação e

    otimização de código Juliano Alves @vonjuliano juliano-alves.com
  2. Quem sou eu? • CTO na broad.app Em uma jornada

    por modularização Amante de linguagens funcionais • As maneiras Scala, Clojure, Elixir • As clássicas Java, C#, Python, Ruby @vonjuliano juliano-alves.com
  3. contexto tradução regra Quill AST quote { query[Fruit].filter(f => true)

    } SELECT f.* FROM Fruit WHERE true SELECT f.* FROM Fruit WHERE (1 = 1)
  4. SELECT c.nome, c.idade − g.idade, FROM cachorro c, gato g

    WHERE c.nome = g.nome AND c.idade > g.idade
  5. for { c <- cachorros g <- gatos if (c.nome

    == g.nome && c.idade > g.idade) } yield { (c.nome, c.idade - g.idade) } quote { }
  6. Abstract syntax trees são estruturas de dados usadas em compiladores

    para representar a estrutura do código ... É frequentemente usada como uma representação intermediária do programa https://en.wikipedia.org/wiki/Abstract_syntax_tree
  7. scala> case class Piloto(nome: String, idade: Int) scala> val pilotos

    = List[Pessoa](Piloto("Rogerinho", 36)) scala> import reflect.runtime.universe._ scala> showRaw(reify(pilotos).tree)
  8. Apply( TypeApply( Select( Ident(scala.collection.immutable.List), TermName("apply") ), List( Select( Select(Select(Ident($line3.$read), TermName("$iw")),

    TermName("$iw")), TypeName("Piloto"))) ), List( Apply( Select(Select(Select(Select(Ident($line3.$read), TermName("$iw")), TermName("$iw")), TermName("Piloto")), TermName("apply")), List(Literal(Constant("Rogerinho")), Literal(Constant(36))))) )
  9. scala> case class Pessoa(id: Int, nome: String, idade: Int) scala>

    case class Endereco(fk: Option[Int], rua: String, numero :Int) scala> import io.getquill._ scala> val ctx = new SqlMirrorContext(PostgresDialect, Literal) scala> import ctx._
  10. scala> val q1 = quote { query[Pessoa] } scala> pprint.pprintln(q1.ast)

    Entity("Pessoa", List()) scala> pprint.pprintln(ctx.run(q1).string) "SELECT x.id, x.nome, x.idade FROM Pessoa x"
  11. scala> val q2 = quote { query[Pessoa] .filter(_.idade > 25)

    } scala> pprint.pprintln(q2.ast) Filter( Entity("Pessoa", List()), Ident("x1"), BinaryOperation( Property(Ident("x1"), "idade"), >, Constant(25) ) ) scala> pprint.pprintln(ctx.run(q2).string) "SELECT x1.id, x1.nome, x1.idade FROM Pessoa x1 WHERE x1.idade > 25"
  12. scala> val q3 = quote { | query[Pessoa].filter(_.idade > 25).map(_.nome)

    | } scala> pprint.pprintln(q3.ast) Map( Filter( Entity("Pessoa", List()), Ident("x1"), BinaryOperation( Property(Ident("x1"), "idade"), >, Constant(25)) ), Ident("x2"), Property(Ident("x2"), "nome") )
  13. scala> val q4 = quote { | query[Pessoa] | .leftJoin(query[Endereco])

    | .on((p, e) => e.fk.exists(_ == p.id)) | .map {case (p, e) => (p.nome, a.flatMap(_.fk))} | } scala> pprint.pprintln(q4.ast)
  14. Map( Join( LeftJoin, Entity("Pessoa", List()), Entity("Endereco", List()), Ident("p"), Ident("e"), OptionExists(Property(Ident("e"),

    "fk"), Ident("x1"), BinaryOperation(Ident("x1"), ==, Property(Ident("p"), "id"))) ), Ident("x01"), Tuple( List( Property(Property(Ident("x01"), "_1"), "nome"), OptionTableFlatMap(Property(Ident("x01"), "_2"), Ident("x2"), Property(Ident("x2"), "fk")) ) ) )
  15. contexto quote { query[Pessoa].map(p => if (true) true else false)

    } SELECT CASE WHEN true THEN true ELSE false END FROM Pessoa p SELECT CASE WHEN 1=1 THEN 1=1 ELSE 1=0 END FROM Pessoa p SELECT CASE WHEN 1=1 THEN 1 ELSE 0 END FROM Pessoa p
  16. sealed trait Ast { def quat: Quat } sealed trait

    Quat class Product(...) extends Quat case object Null extends Quat case object Generic extends Quat case object Unknown extends Quat sealed trait Primitive extends Quat case object Value extends Primitive sealed trait Boolean extends Primitive case object BooleanValue extends Boolean case object BooleanExpression extends Boolean
  17. scala> case class Cachorro(id: Int, nome: String, idade: Int) scala>

    val q = quote { | (valor: String) => | if (valor == "drinks") | query[Cachorro].filter(_.idade >= 21) | else | query[Cachorro] | } scala> pprint.pprintln(q.ast)
  18. Function( List(Ident("valor")), If( BinaryOperation(Ident("valor"), ==, Constant("drinks")), Filter( Entity("Cachorro", List()), Ident("x1"),

    BinaryOperation( Property(Ident("x1"), "idade"), >=, Constant(21)) ), Entity("Cachorro", List()) ) )
  19. scala> pprint.pprintln(q("drinks").ast) Filter( Entity("Cachorro", List()), Ident("x1"), BinaryOperation( Property(Ident("x1"), "idade"), >=,

    Constant(21)) ) scala> pprint.pprintln(ctx.run(q("drinks")).string) "SELECT x1.id, x1.nome, x1.idade FROM Cachorro x1 WHERE x1.idade >= 21"
  20. // FlattenOptionOperation.scala ast match { // ... case OptionGetOrElse(HasBooleanQuat(OptionMap(ast, alias,

    body)), HasBooleanQuat(alternative)) => val expr = BetaReduction(body, alias -> ast) val output: Ast = (IsNotNullCheck(ast) +&&+ expr) +||+ (IsNullCheck(ast) +&&+ alternative) apply(output) case OptionGetOrElse(ast, body) => apply(If(IsNotNullCheck(ast), ast, body)) // ... }
  21. scala> case class Tarefa(id: Int, op1: Option[String], op2: Option[String]) scala>

    val q = quote { | query[Tarefa].filter(t => | t.op1.orElse(t.op2).exists(_ == "cleanup") | ) | } scala> pprint.pprintln(ctx.run(q).string) "SELECT t.id, t.op1, t.op2 FROM Tarefa t WHERE t.op1 = 'cleanup' AND t.op1 IS NOT NULL OR t.op2 = 'cleanup' AND t.op2 IS NOT NULL"
  22. Compiladores são amigos Estruturas e como funcionam Linguagens O que

    acontece no backstage Manipulação de código Mas somente quando necessário! Introduza informação Use a informação introduzida para "encontrar atalhos" Otimização
  23. Fazendo o compilador trabalhar por você: técnicas de manipulação e

    otimização de código Juliano Alves @vonjuliano juliano-alves.com Obrigado!