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.

6b8d8f84c065846e8ec1f12f67d79991?s=128

Juliano Alves

December 28, 2020
Tweet

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. https://broad.app

  4. None
  5. None
  6. None
  7. None
  8. None
  9. https://hipsters.tech/scala-hipsters-210/

  10. https://getquill.io http://homepages.inf.ed.ac.uk/slindley/papers/practical-theory-of-linq.pdf

  11. Quill: Arquitetura

  12. Quill: Arquitetura

  13. Quill: Arquitetura

  14. Linguagens

  15. Código substantivo adjetivo limpo

  16. contexto tradução regra substantivo adjetivo substantivo adjetivo Código limpio Clean

    code Código limpo
  17. 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)
  18. Manipulação de código

  19. SELECT c.nome, c.idade − g.idade, FROM cachorro c, gato g

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

    == g.nome && c.idade > g.idade) } yield { (c.nome, c.idade - g.idade) } quote { }
  21. Quill: Arquitetura

  22. 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
  23. https://stackoverflow.com/questions/14790115/where-can -i-learn-about-constructing-asts-for-scala-macros

  24. 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)
  25. 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))))) )
  26. Quill AST (semi) completa

  27. Quill: Arquitetura

  28. 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._
  29. 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"
  30. 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"
  31. 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") )
  32. scala> pprint.pprintln(ctx.run(q3).string) "SELECT x1.nome FROM Pessoa x1 WHERE x1.idade >

    25"
  33. 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)
  34. 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")) ) ) )
  35. scala> pprint.pprintln(ctx.run(q4).string) "SELECT p.nome, a.fk FROM Pessoa p LEFT JOIN

    Endereco e ON e.fk = p.id"
  36. Informação provida

  37. case class Pessoa(id: Long) val q = quote { query[Pessoa].map(p

    => if (true) true else false )
  38. 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
  39. Quill AST

  40. 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
  41. Introduza informação Não tente "adivinhar" Tome cuidado!

  42. Otimizações

  43. 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)
  44. 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()) ) )
  45. scala> pprint.pprintln(q("drinks").ast) If( BinaryOperation(Constant("drinks"), ==, Constant("drinks")), Filter( Entity("Cachorro", List()), Ident("x1"),

    BinaryOperation( Property(Ident("x1"), "idade"), >=, Constant(21)) ), Entity("Cachorro", List()) )
  46. 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"
  47. scala> pprint.pprintln(q("ki-suco").ast) Entity("Cachorro", List()) scala> pprint.pprintln(ctx.run(q("ki-suco")).string) "SELECT x1.id, x1.nome, x1.idade

    FROM Cachorro x1"
  48. Option.orElse Option.getOrElse

  49. // 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)) // ... }
  50. 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"
  51. Conclusão

  52. 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
  53. https://getquill.io "This is the project you are looking for"

  54. Dúvidas?

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

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