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

Scheme nella programmazione embedded - Marco Be...

Scheme nella programmazione embedded - Marco Benelli

Avatar for Better Embedded

Better Embedded

September 25, 2012
Tweet

More Decks by Better Embedded

Other Decks in Technology

Transcript

  1. Lisp • Uno dei primi linguaggi ad alto livello (1958)

    • LISt Processor • Lots of Irritants Superfluous Parentheses • Tree-data structure (vs array) • Pionere: dynamic typing, garbage collector, funzioni first class... • Compilatori self-hosted • Code is data
  2. Lisp in sistemi embedded? Lisp is good for: Current Lisp

    implementation are not so good for: • Persistent storage • Maximizing resource on small machines • Projects with hundreds of programmers • Close communication with foreign code • Delivering small-image applications • Real-time control • Projects with inexperienced Lisp programmers • Some kind of numerical computation • Exploratory Programming • Rapid Prototyping • Minimizing type to market • Single-digit team projects • Compilers & translator • Dynamic dispatch & creation • Tight integration of modules • High degree of interaction • User extensibility Norvig & Pitman – Tutorial on Good Lisp Programming Style - 1993
  3. Scheme Programming languages should be designed not by piling feature

    on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.
  4. Scheme • Sintassi semplice, s-expr • Tipizzazione dinamica, garbage collector,

    first-class functions • Programmazione funzionale ed imperativa • Metaprogrammazione: macros • Tail-calls • First-class continuations: un'unica struttura di controllo con cui costruire coroutines, threads, eccezioni … • Lambda calcolo → compilatori semplici ed efficienti (RABBIT - 1978)
  5. Esempi '(0 1 2 3) => (O 1 2 3)

    (define pi 3.14159) (define (fib n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))) (fib 40) => 165580141 (with-output-to-string “Foo: “ (lambda () (for-each display (intersperse (iota 5) “, “)))) => “Foo: 0, 1, 2, 3, 4”
  6. Esempi (define-macro (push! x xs) `(set! ,xs (cons ,x ,xs)))

    (define stack '()) (push! 0 stack) → (set! stack (cons 0 stack)) stack => (0) (push! 1 stack) → (set! Stack (cons 1 stack)) stack => (1 0)
  7. Implementazioni Più di 50 implementazioni, tra cui una decina di

    sistemi maturi • Compilatori nativi: MIT/GNU, Chez, Larceny... • Interpreti/VM: Scheme48, Gauge, Kawa... • Compilatori con target C: Gambit, Chicken, Bigloo ...
  8. Gambit • Obbiettivi: • Conforme allo standard (R5RS) • Affidabile

    • Portabile • Efficiente • Pragmatico • Agnostico (non impone un particolare stile di programmazione)
  9. GSI e GSC • Due programmi principali: • Gsi: interprete,

    ottimo per il debug, ma non efficiente • Gsc: compilatore, include l'interprete • Possibità di miscelare liberamente codice compilato ed interpretato
  10. Compilatore • Default backend: C • Genera codice C indipendente

    dal processore, dal compilatore e dal sistema operativo • Il codice è compilabile da qualsiasi compilatore C/C++/objC, su processori a 32 e 64 bit, qualsiasi endianess • Uso di trampolini per supportare tail calls • Altri backend (in sviluppo): x86, ARM, javascript, “universal”
  11. Dipendenze • Scheme-in-scheme: primitive, interprete, debugger, bignums... • ~30% del

    codice sorgente di Gambit non è scritto in scheme ma in C (no ASM), principalmente riguarda l'interfaccia con il SO • Il runtime dipende esclusivamente dalle librerie standard C (clib) • Le applicazioni possono essere distribuite come insieme di “.c” files, Gambit non è richesto sul sistema target
  12. Estensioni • Dichiarazioni • Namespaces • Threads, I/0, serializzazione •

    Foreign Function Interface (FFI) • Homogenous vectors • Records • Optional and key parameters • Infix notation • ...
  13. Dichiarazioni Variazioni alla semantica di R5RS (car x) ;; 1-

    legge la variabile globale “car” ;; 2- verifica che sia una funzione ;; 3- chiama la funzione (declare (standard-bindings)) (car x) ;; Il compilatore sa che “car” ha il ;; significato predefinito ;; e può mettere la chiamata inline
  14. Esempi di dichiarazioni (block) ; le variabili globali definite ;

    in questo file non vengono mutate (fixnum) ; utilizza solo artimetica fixed (flonum) ; utilizza solo aritmetica float (not safe) ; disabilita il type-checking (debug) ; genera informazioni aggiuntive (not proper-tail-calls) ; disabilita tco (not interrupts-enable) ; disabilita interrupts checks ; (usare con cautela!)
  15. Performance • Nuberi di fibonacci, versione naïve, (fib 40), risultati

    in secondi: Senza dichiarazioni → 20.43 + standard-bindings → 13.22 + block → 9.48 + fixnum → 11.09 (?!?) + not safe → 3.68 • gcc -O2 → 1.96
  16. Threads • Lightweight threads: – 1 thread = descriptor (324

    bytes) + continuation – Thread creation/syncrhonization ~ 0.5 μs – Support millions of active threads (in ~ 1GB) • Preempitve scheduler con priorità, implementato in scheme: – Suspension: call/cc – Preemption: heartbeat interrupts • SRFI-21 “Real-time multithreading”: threads, mutex, mailboxes, condition-variables
  17. Esempi (define-macro (with-mutex mutex . body) (let ((m (gensym)) (r

    (gensym))) `(let ((,m ,mutex)) (mutex-lock! ,m #f #f) (let ((,r (begin ,@body))) (mutex-unlock! ,m) ,r)))) (define (active-alarms) (with-mutex db-mutex (fold/query (lambda (seed . cols) (values #t (cons cols seed))) '() (sql (select (id msg) (from alarms) (where (= status “active”)))))))
  18. I/O • Compatibile con lo standard scheme • Estensioni: •

    Encodings • I/O binario • Nonblocking I/O • Port types: file, directory, OS processes, TCP client, TCP server, string, vector, bytevector, pipe, ...
  19. Esempi (define http-server-start! (lambda (hs) (let ((server-port (open-tcp-server (list server-address:

    '#u8(0 0 0 0) port-number: (server-port-number hs) backlog: 128 reuse-address: #t char-encoding: 'ISO-8859-1)))) (accept-connections hs server-port))))
  20. Foreign Function Interface • Type definition: (c-define-type sqlite3 (struct “sqlite3”))

    (c-define-type sqlite3* (pointer sqlite3)) • Chiamate a funzioni C: (define sqlite3-errcode (c-lambda (sqlite3*) int “sqlite3_errcode”)) • Chiamate a funzioni Scheme: (c-define (eval-string str) (char-string) char-string “eval_string” “” (object->string (eval (with-input-from-string str read))))
  21. Esempi (define sqlite3-open (c-lambda (char* sqlite3**) int “sqlite3_open”)) (define %sqlite3-open

    (c-lambda (char*) sqlite3* #<<C-END sqlite3* db; int res = sqlite3_open(___arg1, &db); ___result_voidstar = db; C-END ))
  22. Homogenous vectors • Vettori di integer o float di dimensione

    fissa (define v (make-f64vector 10 3.1416)) (f64vector-set! v 0 (* 2 (f64vector-ref v 0))) ;; u8vector unsigned integers ;; u16vector ;; u32vector ;; u64vector ;; s8vector signed integers ;; s16vector ;; s32vector ;; s64vector ;; f32vector floating point numbers ;; f64vector
  23. Esempi (define (send-write-request! fc ui n offset port) (u8vector-set! *send-buffer*

    5 6) (u8vector-set! *send-buffer* 6 ui) (u8vector-set! *send-buffer* 7 fc) (u8vector-set! *send-buffer* 9 offset) (u8vector-set! *send-buffer* 10 (extract-bit-field 8 8 n)) (u8vector-set! *send-buffer* 11 (extract-bit-field 8 0 n)) (write-subu8vector *send-buffer* 0 (u8vector-length *send-buffer*) port) (force-output port))
  24. Serializzazione • Gli oggetti scheme possono essere serializzati in byte-vectors

    • Closure, continuations, strutture cicliche • Utilizzate per computazione distrubuiti (es: termite) • Sorgente e destinazione possono differire per sistema operativo, processore, word-size, endianess... • Possibilità di definire encoders/decoders per oggetti non serializzabili univocamente (ports, threads...)
  25. Memory Management • MOVABLE object: oggetti piccoli, continuation frames →

    stop-and-copy compacting GC • STILL object: oggetti grandi, oggetti allocati tramite FFI → reference count, mark-sweep GC
  26. SCADA Supervisor Control And Data Acquisition • Sensors / Actuators

    • Microcontrollers (PLCs) • Supervisor • Human Machine Interface Image from wikipedia
  27. Piattaforme • ARM, GNU/Linux • X86, GNU/Linux • SH-2, uClinux

    (no MMU) CPU: from 200Mhz to >1Ghz RAM: from 128Mb to 1Gb
  28. Klio Tools • Librerie dalla comunità Scheme (SRFIs, irregex, SSAX,

    …) • Librerie da Gambit (base64, http, …) • Librerie custom (sqlite bindings, csv...) • Web Server • Protocolli usati in sistemi SCADA (fetchwrite, modbus)
  29. Klio Web Server • Basato sul web server incluso in

    Gambit • Esteso per essere conforme a HTTP 1.1 • Nato come ambiente di test • Ottimizzato per applicazioni desktop-like
  30. FFI: sqlite bindings (define sqlite3-open (c-lambda (char* sqlite3**) int “sqlite3_open”))

    (define %sqlite3-open (c-lambda (char*) sqlite3* #<<C-END sqlite3* db; int res = sqlite3_open(___arg1, &db); ___result_voidstar = db; C-END )) (define (open name) (let ((db (%sqlite-open name))) (if (zero? (sqlite3-errcode db)) db (raise (sqlite3-errmsg db)))))
  31. Klio Scada • Implementazione dei protocolli tipicamente usati in applicazioni

    Scada (modbus, fetchwrite) in Scheme • Una singola applicazione contiene il web server e l'unità di acquisizione (comunicazione con il PLC) • Unico punto di accesso al db, concorenza gestita dallo scheduler di Gambit (più efficient del locking di sqlite) • Ultimi dati acquisiti immediatamente disponibili al client, senza necessità di accesso al db) • Non (ancora) in produzione.
  32. Gambit su dispositivi mobili • IOS • Poichè Gambit compila

    in C, le applicazioni scritte in Gambit sono ammesse dalle condizioni Apple • Applicazioni esistenti: Farmageddon (gioco 3D), Reversi (gioco strategico), Gambit REPL (sviluppo/educazione) • Possibilitá di sviluppo interattivo grazie al remote REPL, ad esempio connetendosi con Emacs • Infrastruttura di sviluppo inclusa nella distribuzione standard di Gambit.
  33. Android • Possibilitá di compilare Gambit su Android usando la

    JNI ed il relativo kit di sviluppo • Gambit REPL giá disponibile sull'AppStore
  34. Riferimenti • Scheme Wiki community.schemewiki.org • ReadScheme http://www.readscheme.org/ • SRFIs

    http://www.srfi.org/ • Gambit Wiki http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page • Gambit-C Inside-Out • Gambit REPL • Distributed Computing with Gambit • Klio http://mbenelli.github.com/klio