hanging process pasted by klm` on Sun Jan 31 12:10:51 2016

my chicken-program is unresponsive. it's using 100% cpu:

$ sudo top | grep 27547
27547 klm       20   0 3190660 1.713g   2744 R  92.8  3.6   4114:02 arp-boats 


$ sudo strace -p 27547
Process 27547 attached
munmap(0x7f4e3394b000, 1073745920)      = 0
munmap(0x7f4e7394c000, 1073745920)      = 0
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e7394c000
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e3394b000
munmap(0x7f4df394a000, 1073745920)      = 0
munmap(0x7f4e7394c000, 1073745920)      = 0
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e7394c000
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4df394a000
munmap(0x7f4e3394b000, 1073745920)      = 0
munmap(0x7f4e7394c000, 1073745920)      = 0
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e7394c000
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4e3394b000
....
...


$ sudo gdb -p 27547
(gdb) bt
#0  0x00007f4eb67d280c in really_remark () from /usr/local/lib/libchicken.so.8
#1  0x00007f4eb67d2e9e in C_rereclaim2 () from /usr/local/lib/libchicken.so.8
#2  0x00007f4eb67d4259 in allocate_vector_2 () from /usr/local/lib/libchicken.so.8
#3  0x00007f4eb67d5d23 in CHICKEN_run () from /usr/local/lib/libchicken.so.8
#4  0x00007f4eb67d5df0 in CHICKEN_main () from /usr/local/lib/libchicken.so.8
#5  0x00007f4eb619aec5 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#6  0x0000000000401333 in _start ()

no title pasted by anonymous on Sun Jan 31 12:11:28 2016

$ csi -version

CHICKEN
(c) 2008-2015, The CHICKEN Team
(c) 2000-2007, Felix L. Winkelmann
Version 4.10.1 (rev 274e7af)
linux-unix-gnu-x86-64 [ 64bit manyargs dload ptables ]
compiled 2015-12-02 on carmine (Linux)

now with DEBUGBUILD pasted by klm` on Thu Feb 4 11:09:10 2016

- This happens with DEBUGBUILD too
- This happens both with csc and csi (but still using compiled eggs, obviously)


(gdb) bt
#0  C_rereclaim2 (size=1073741816, relative_resize=0) at runtime.c:3503
#1  0x00007f93e3de7435 in allocate_vector_2 (c=6, av=0x7fffb2ebf5c0) at runtime.c:7483
#2  0x00007f93e3dc55cc in CHICKEN_run (toplevel=0x0) at runtime.c:1499
#3  0x00007f93e3dc2a48 in CHICKEN_main (argc=2, argv=0x7fffb2ebf798, toplevel=0x4123d1 <C_toplevel>) at runtime.c:585
#4  0x00000000004123cf in main (argc=2, argv=0x7fffb2ebf798) at arp-boats.c:3736


arp-boats.scm pasted by klm` on Thu Feb 4 11:17:35 2016

;;;  see next comments on how to start this

;; boat service:
(use matchable medea spiffy uri-common intarweb comparse intarweb)
;; (server-port 8888)
(match (command-line-arguments)
  ((port)
   (server-port (string->number port)))
  (else (print "usage: \n
- send geojson (boats) on stdin.
- /arp-boats REST interface")
        (exit 1)))

;; workaround for blocking on i/o when reading json from stdin
(include "nonblocking-input-ports.scm")
(current-input-port (open-input-file*/nonblock 0))

;; ==================== debug

(thread-start! (lambda () (use nrepl) (nrepl 1234)))


;; ==================== utils

;; ==================== reser ====================
;; TODO: release reser egg and make don't embed it here
(define (request-string!)
  ;; TODO: what to do is we have more than 16MB? we can't just ignore it all.
  (read-string (min (* 16 1024 1024) ;; <- max 16MB
                    (or (header-value 'content-length (request-headers (current-request))) 0))
               (request-port (current-request))))

(define (reser-handler handler)

  (define request `((body    . ,(request-string!))
                    (uri     . ,(request-uri (current-request)))
                    (headers . ,(request-headers (current-request)))
                    (method  . ,(request-method (current-request)))))

  (define resp (handler request))

  (send-response body:    (or (alist-ref 'body resp) "")
                 status:  (alist-ref 'status resp)
                 code:    (alist-ref 'code resp)
                 reason:  (alist-ref 'reason resp)
                 headers: (or (alist-ref 'headers resp) '())))
;; construct a response object
(define (response #!key body status code reason headers)
  `((body    . ,body)
    (status  . ,status)
    (code    . ,code)
    (reason  . ,reason)
    (headers . ,headers)))

;; call handler with an exception handler, and log error to request
;; response instead of stderr.
(define ((wrap-errors handler) r)
  (handle-exceptions
   exn
   (response body: (conc (get-condition-property exn 'exn 'message) ": "
                         (get-condition-property exn 'exn 'arguments) "\n"
                         (with-output-to-string (lambda () (pp (condition->list exn)))))
             status: 'bad-request)
   (handler r)))

;; append \n at end of server response. makes it terminal friendly
(define ((wrap-trailing-newline handler) r)
  (let ((resp (handler r)))
    (alist-update 'body (string-append (or (alist-ref 'body resp) "") "\n") resp)))

;; access domain-name string, use "*" to give everybody access
;; ((wrap-cors-headers "*" (lambda _ (response headers: (headers `((abd "klm")))))) '())
;; ((wrap-cors-headers "*" (lambda _ (response body: "hi"))) '())
(define ((wrap-cors-headers access handler) r)
  (let ((response (handler r)))
    (alist-update 'headers
                  (alist-update 'Access-Control-Allow-Origin
                                (list access)
                                (or (alist-ref 'headers response) '()))
                  response)))

;; ==================== globals

(define state '())

(define (limit lst num)
  (take lst (min (length lst) num)))

;; ==================== boat utils

(define (geojson-mmsi geojson)
  (alist-ref 'mmsi (or (alist-ref 'properties geojson) '())))

;; (pp (extract (include "./boat.data.scm")))

;; input: alist ((pos . (lat . lon)) (mmsi . mmsi))
;; state is a map of :
(define (prj-geojson geojson state)
  ;; set properties for mmsi key:
  (alist-update (geojson-mmsi geojson) ;; key (mmsi)
                geojson ;; value (geojson feature)
                state))

;; (rect-inside? 0 0  1 -1 -1 1)
(define (rect-inside? x y top left bottom right)
  (and (>= x left)   (<= x right)
       (>= y bottom) (<= y top)))

;; (length (filter (lambda (pair) (geojson-inside? (cdr pair) 61 5 60 6)) _state))

(define (geojson-inside? geojson top left bottom right)
  (and-let* ((gm (alist-ref 'geometry geojson))
             (pos (alist-ref 'coordinates gm))
             (lon (vector-ref pos 0))
             (lat (vector-ref pos 1)))
            (and lon lat (rect-inside? lon lat top left bottom right))))

;; query boats based on region (bounding box). typical json is "[60,
;; 5, 61, 5.5]"
(define (bb-query state bbox)
  ;; bad naming here, sorry. need a rect abstraction
  (define (corner x) (vector-ref bbox x))
  (define result
    (filter (lambda (pair)
              (geojson-inside? (cdr pair)
                               (corner 0) (corner 1)
                               (corner 2) (corner 3)))
            state))

  (print ", found " (length result) "/" (length state) " boats")


  (json->string
   `((type . "FeatureCollection")
     (features . ,(list->vector (limit (map cdr result) 100))))))


;; (mmsi-query state `((mmsi . #(257999279 257605000))))
(define (mmsi-query state json)

  (define (->vector x) (if (vector? x) x (vector x)))
  (define (->fixnum x) (if (number? x) x (string->number x)))

  (let ((boats (map ->fixnum
                    (vector->list
                     (->vector
                      (or (alist-ref 'mmsi json)
                          (error "request missing mmsi field")))))))
    (define result (filter (lambda (pair) ;; (mmsi . alist)
                             (member (car pair) boats))
                           state))
    (json->string `((type . "FeatureCollection")
                    (features . ,(list->vector (map cdr result)))))))


(define (query-handler json)
  (print "boats: got query " json)
  (if json
      (if (vector? json)
          (response body: (bb-query state json))
          (response body: (mmsi-query state json)))
      (response status: 'bad-request body: "invalid geojson query" json)))

;; uri to bounding-box query. ie:
;; (uri-bbq (uri-reference "?bb=1/2/3/4"))
;; (uri-bbq (uri-reference "?nothing=false"))
(define (uri-bbq uri)
  (and-let* ((bb (alist-ref 'bb (uri-query uri))))
            (list->vector (map string->number (string-split bb "/")))))

(define (top-handler r)
  (match (uri-path (alist-ref 'uri r))
    (('/ "arp-boats")
     ;; - try picking the bb query parameter from GET request
     ;; - try reading the json payload (POST request)
     (query-handler (or (uri-bbq (alist-ref 'uri r))
                        (read-json (alist-ref 'body r)))))
    (else (response status: 'bad-request))))

;; you can test by evaluating this:
;; (app `((uri . ,(uri-reference "/arp-boats?bb=1/2/3/4")) (body . "")))
(define app (wrap-cors-headers
             "*" ;; give everybody "ajax" access
             (wrap-errors
              (wrap-trailing-newline (lambda (r) (top-handler r))))))


(define server-thread
  (thread-start!
   (lambda ()
     (vhost-map `((".*" . ,(lambda (c) (reser-handler (lambda (r) (app r)))))))
     (start-server))))

(define count 0)
(let loop ((input (current-input-port)))
  (receive (json rest) (read-json input)
    (set! count (add1 count))
    (set! state (prj-geojson json state))
    (if (not (parser-input-end? rest))
        (loop rest))))


nonblocking-input-ports.scm pasted by klm` on Thu Feb 4 11:18:17 2016

;;; see next comments for how to use


;;; this is a workaround for blocking calls to read-char on
;;; current-input-port.

(use posix)
;; like open-input-file* but doesn't block other threads. obs: this
;; port isn't thread-safe (it may block all threads if used from
;; multiple threads). it's buffered, but not thread-safe. fd can be 0
;; for stdin.
(define (open-input-file*/nonblock fd)
  (##sys#file-nonblocking! fd)
  (define buffer '())
  (make-input-port
   (lambda ()
     (let retry ()
       (if (pair? buffer)
           (let ((head (car buffer)))
             (set! buffer (cdr buffer))
             head)
           ;; fill buffer and retry
           (begin
             (thread-wait-for-i/o! fd #:input)
             (let* ((r (file-read fd 1024))
                    (bytes (cadr r))
                    (data (substring (car r) 0 bytes)))
               (if (= 0 bytes) ;; we just waited for 0 bytes => eof
                   #!eof
                   (begin (set! buffer (string->list data))
                          (retry))))))))
   (lambda () (file-select fd #f 0))
   (lambda () (file-close fd))))

how to reproduce pasted by klm` on Thu Feb 4 11:24:20 2016

;;; in our production, we get geojson data from real boats.
;;; but we can reproduce the problem with 
;;; "mock geojson" like this:


(use medea)

(let loop ()
  (write-json
   `((type . "Feature")
     (geometry . ((type . "Point")
                  (coordinates . ,(vector (/ (random 10000) 100) (/ (random 10000) 100)))))
     (properties . ((mmsi . ,(random 10000))
                    (name . "debug")
                    (sog . 5)))))
  (newline)
  (loop))

;;; so to start this thing, do this:
;;; csi -s geojson-generator.scm  | csi -s arp-boats.scm 8181
;; then, in another terminal, see that the mock boats show up:
;;; curl "localhost:8181/arp-boats?fleet=&bb=67.1016555307692/-28.256835937499996/53.61857936489517/46.669921875"
;;; {"type":"FeatureCollection","features":[{"type":"Feature","geometry":
;;; {"type":"Point","coordinates":[31.56,60.76]},"properties":......

;;; Great, it's running and working. Now wait patiently, and after about 1-2 days, the arp-boats.scm program will hang forever in a GC loop for some reason.

no title pasted by klm` on Fri Feb 5 09:17:00 2016

It hangs on chicken 4.10.0 too. And with the -:g and -:d flags, we see this:

[debug] resizing heap dynamically from 2097151k to 2097151k ...
[GC] (old) fromspace: 	start=0x00007f07e6cfe010, 	limit=0x00007f0826cfe008
[GC] (old) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[GC] resized heap to 2147483632 bytes
[GC] (new) fromspace: 	start=0x00007f0826cff010, 	limit=0x00007f0866cff008
[GC] (new) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[debug] resizing heap dynamically from 2097151k to 2097151k ...
[GC] (old) fromspace: 	start=0x00007f0826cff010, 	limit=0x00007f0866cff008
[GC] (old) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[GC] resized heap to 2147483632 bytes
[GC] (new) fromspace: 	start=0x00007f07e6cfe010, 	limit=0x00007f0826cfe008
[GC] (new) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[debug] resizing heap dynamically from 2097151k to 2097151k ...
[GC] (old) fromspace: 	start=0x00007f07e6cfe010, 	limit=0x00007f0826cfe008
[GC] (old) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[GC] resized heap to 2147483632 bytes
[GC] (new) fromspace: 	start=0x00007f0826cff010, 	limit=0x00007f0866cff008
[GC] (new) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008
[debug] resizing heap dynamically from 2097151k to 2097151k ...
[GC] (old) fromspace: 	start=0x00007f0826cff010, 	limit=0x00007f0866cff008
[GC] (old) tospace:   	start=0x00007f0866d00010, 	limit=0x00007f08a6d00008

GC debug output pasted by klm` on Fri Feb 5 09:29:52 2016



Just trying to pick out the interesting parts of this run. So after 89706 major GC's, it starts to fail:

(first column is line-number)

 372508 [GC] 0 locatives (from 32)
 372509 [GC] level  1   gcs(minor)  6   gcs(major)  74456
 372510 [GC] stack      0x00007fffd2a86920      0xffffffffd2a868e0      0x00007fffd2b86920
 372511 [GC]  from      0x00007f08768bb010      0x00007f08a6c03e30      0x00007f08a6d00119      0x0000000030348e20
 372512 [GC]    to      0x00007f0845e68010      0x00007f0845e68010      0x00007f08762ad119 
 372513 [GC] 0 locatives (from 32)
 372514 [debug] resizing heap dynamically from 1581608k to 2097151k ...
 372515 [GC] (old) fromspace:   start=0x00007f08768bb010,       limit=0x00007f08a6d00119
 372516 [GC] (old) tospace:     start=0x00007f0845e68010,       limit=0x00007f08762ad119
 372517 [GC] resized heap to 2147483632 bytes
 372518 [GC] (new) fromspace:   start=0x00007f0805e67010,       limit=0x00007f0845e67008
 372519 [GC] (new) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 372520 [GC] level  1   gcs(minor)  2822        gcs(major)  74457
 372521 [GC] stack      0x00007fffd2a86920      0xffffffffd2a86820      0x00007fffd2b86920
 372522 [GC]  from      0x00007f0866d00010      0x00007f089706b420      0x00007f08a6d00008      0x000000003036b410
 372523 [GC]    to      0x00007f0805e67010      0x00007f0805e67010      0x00007f0845e67008 
 372524 [GC] 0 locatives (from 32)
 372525 [GC] level  1   gcs(minor)  2808        gcs(major)  74458
 372526 [GC] stack      0x00007fffd2a86920      0xffffffffd2a86820      0x00007fffd2b86920
 372527 [GC]  from      0x00007f0805e67010      0x00007f08361ddb00      0x00007f0845e67008      0x0000000030376af0
 372528 [GC]    to      0x00007f0866d00010      0x00007f0866d00010      0x00007f08a6d00008 
 372529 [GC] 0 locatives (from 32)
 372530 [GC] level  1   gcs(minor)  2765        gcs(major)  74459
 372531 [GC] stack      0x00007fffd2a86920      0xffffffffd2a86980      0x00007fffd2b86920
 372532 [GC]  from      0x00007f0866d00010      0x00007f089700ecb8      0x00007f08a6d00008      0x000000003030eca8
 372533 [GC]    to      0x00007f0805e67010      0x00007f0805e67010      0x00007f0845e67008 
 372534 [GC] 0 locatives (from 32)





 448744 [GC] 0 locatives (from 32)
 448745 [GC] level  1   gcs(minor)  21  gcs(major)  89702
 448746 [GC] stack      0x00007fffd2a86920      0xffffffffd2a867f0      0x00007fffd2b86920
 448747 [GC]  from      0x00007f0805e67010      0x00007f0845d55f00      0x00007f0845e67008      0x000000003feeeef0
 448748 [GC]    to      0x00007f0866d00010      0x00007f0866d00010      0x00007f08a6d00008 
 448749 [GC] 0 locatives (from 32)
 448750 [GC] level  1   gcs(minor)  9   gcs(major)  89703
 448751 [GC] stack      0x00007fffd2a86920      0xffffffffd2a867e0      0x00007fffd2b86920
 448752 [GC]  from      0x00007f0866d00010      0x00007f08a6c00928      0x00007f08a6d00008      0x000000003ff00918
 448753 [GC]    to      0x00007f0805e67010      0x00007f0805e67010      0x00007f0845e67008 
 448754 [GC] 0 locatives (from 32)
 448755 [GC] level  1   gcs(minor)  17  gcs(major)  89704
 448756 [GC] stack      0x00007fffd2a86920      0xffffffffd2a867b0      0x00007fffd2b86920
 448757 [GC]  from      0x00007f0805e67010      0x00007f0845d59990      0x00007f0845e67008      0x000000003fef2980
 448758 [GC]    to      0x00007f0866d00010      0x00007f0866d00010      0x00007f08a6d00008 
 448759 [GC] 0 locatives (from 32)
 448760 [GC] level  1   gcs(minor)  7   gcs(major)  89705
 448761 [GC] stack      0x00007fffd2a86920      0xffffffffd2a86800      0x00007fffd2b86920
 448762 [GC]  from      0x00007f0866d00010      0x00007f08a6c1ec28      0x00007f08a6d00008      0x000000003ff1ec18
 448763 [GC]    to      0x00007f0805e67010      0x00007f0805e67010      0x00007f0845e67008 
 448764 [GC] 0 locatives (from 32)
 448765 [GC] level  1   gcs(minor)  0   gcs(major)  89706
 448766 [GC] stack      0x00007fffd2a86920      0xffffffffd2a868c0      0x00007fffd2b86920
 448767 [GC]  from      0x00007f0805e67010      0x00007f0845d70cd8      0x00007f0845e67008      0x000000003ff09cc8
 448768 [GC]    to      0x00007f0866d00010      0x00007f0866d00010      0x00007f08a6d00008 
 448769 [GC] 0 locatives (from 32)
 448770 [debug] resizing heap dynamically from 2097151k to 2097151k ...
 448771 [GC] (old) fromspace:   start=0x00007f0805e67010,       limit=0x00007f0845e67008
 448772 [GC] (old) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 448773 [GC] resized heap to 2147483632 bytes
 448774 [GC] (new) fromspace:   start=0x00007f07c5e66010,       limit=0x00007f0805e66008
 448775 [GC] (new) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 448776 [debug] resizing heap dynamically from 2097151k to 2097151k ...
 448777 [GC] (old) fromspace:   start=0x00007f07c5e66010,       limit=0x00007f0805e66008
 448778 [GC] (old) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 448779 [GC] resized heap to 2147483632 bytes
 448780 [GC] (new) fromspace:   start=0x00007f0826cff010,       limit=0x00007f0866cff008
 448781 [GC] (new) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 448782 [debug] resizing heap dynamically from 2097151k to 2097151k ...
 448783 [GC] (old) fromspace:   start=0x00007f0826cff010,       limit=0x00007f0866cff008
 448784 [GC] (old) tospace:     start=0x00007f0866d00010,       limit=0x00007f08a6d00008
 448785 [GC] resized heap to 2147483632 bytes

hanging version w/o Spiffy pasted by sjamaan on Fri Feb 5 10:28:57 2016

;;;  see next comments on how to start this

;; boat service:
(use srfi-18 medea comparse)

;; workaround for blocking on i/o when reading json from stdin
(include "nonblocking-input-ports.scm")
(current-input-port (open-input-file*/nonblock 0))

;; ==================== globals

(define state '())

(define (limit lst num)
  (take lst (min (length lst) num)))

;; ==================== boat utils

(define (geojson-mmsi geojson)
  (alist-ref 'mmsi (or (alist-ref 'properties geojson) '())))

;; (pp (extract (include "./boat.data.scm")))

;; input: alist ((pos . (lat . lon)) (mmsi . mmsi))
;; state is a map of :
(define (prj-geojson geojson state)
  ;; set properties for mmsi key:
  (alist-update (geojson-mmsi geojson) ;; key (mmsi)
                geojson ;; value (geojson feature)
                state))

;; (rect-inside? 0 0  1 -1 -1 1)
(define (rect-inside? x y top left bottom right)
  (and (>= x left)   (<= x right)
       (>= y bottom) (<= y top)))

;; (length (filter (lambda (pair) (geojson-inside? (cdr pair) 61 5 60 6)) _state))

(define (geojson-inside? geojson top left bottom right)
  (and-let* ((gm (alist-ref 'geometry geojson))
             (pos (alist-ref 'coordinates gm))
             (lon (vector-ref pos 0))
             (lat (vector-ref pos 1)))
            (and lon lat (rect-inside? lon lat top left bottom right))))

;; query boats based on region (bounding box). typical json is "[60,
;; 5, 61, 5.5]"
(define (bb-query state bbox)
  ;; bad naming here, sorry. need a rect abstraction
  (define (corner x) (vector-ref bbox x))
  (define result
    (filter (lambda (pair)
              (geojson-inside? (cdr pair)
                               (corner 0) (corner 1)
                               (corner 2) (corner 3)))
            state))

  (print "found " (length result) "/" (length state) " boats")

  (json->string
   `((type . "FeatureCollection")
     (features . ,(list->vector (limit (map cdr result) 100))))))

(define (query-handler json)
  (print "boats: got query " json)
  (bb-query state json))

;; uri to bounding-box query. ie:
;; (uri-bbq (uri-reference "?bb=1/2/3/4"))
;; (uri-bbq (uri-reference "?nothing=false"))
(define (get-bbq bb)
  (list->vector (map string->number (string-split bb "/"))))

(define (top-handler)
  (query-handler
   (get-bbq "67.1016555307692/-28.256835937499996/53.61857936489517/46.669921875")))

(define server-thread
  (thread-start!
   (lambda ()
     (let lp ()
       (thread-sleep! 0.01)
       (print "boats!" (top-handler))
       (lp)))))

(define count 0)
(let loop ((input (current-input-port)))
  (receive (json rest) (read-json input)
    (set! count (add1 count))
    (set! state (prj-geojson json state))
    (if (not (parser-input-end? rest))
        (loop rest))))

no title pasted by anonymous on Fri Feb 5 10:41:25 2016

this one hangs after about 5 minutes:
$ csi -s geojson-generator.scm | csi -s ./arp-boats.scm -:g -:hm16M 2>&1 | grep resize -C 5



;; boat service:
(use matchable cjson srfi-18)

;; workaround for blocking on i/o when reading json from stdin
(include "nonblocking-input-ports.scm")
(current-input-port (open-input-file*/nonblock 0))

;; ==================== debug

(thread-start! (lambda () (use nrepl) (nrepl 1234)))


;; ==================== globals

(define state '())

;; ==================== boat utils

(define (geojson-mmsi geojson)
  (let ((mmsi (alist-ref 'mmsi (or (alist-ref 'properties geojson) '()))))
    (assert (number? mmsi))
    mmsi))

;; (pp (extract (include "./boat.data.scm")))

;; input: alist ((pos . (lat . lon)) (mmsi . mmsi))
;; state is a map of <mmsi>:<properties>
(define (prj-geojson geojson state)
  (assert (<= (length state) 20000))
  ;; set properties for mmsi key:
  (alist-update (geojson-mmsi geojson) ;; key (mmsi)
                geojson ;; value (geojson feature)
                state))

(define count 0)
(port-for-each
 (lambda (line)
   (let ((json (string->json line)))
     (set! count (add1 count))
     (set! state (prj-geojson json state))))
 read-line)


reproducing OOM pasted by klm` on Fri Feb 5 12:18:15 2016


Here's a small snippet that gives us OOM, but it doesn't infinitely hang on GC like previously. No ports or JSON-parsing.

[klm@kth arp]$ cat smallerror.scm 

(define state '())

(define (geojson-mmsi geojson)
  (let ((mmsi (alist-ref 'mmsi (or (alist-ref 'properties geojson) '()))))
    (assert (number? mmsi))
    mmsi))

(define (prj-geojson geojson state)
  (assert (<= (length state) 20000))
  ;; set properties for mmsi key:
  (alist-update (geojson-mmsi geojson) ;; key (mmsi)
                geojson ;; value (geojson feature)
                state))

(let loop ()
  (set! state
        (prj-geojson
         `((type . "Feature")
           (geometry . ((type . "Point")
                        (coordinates . ,(vector (/ (random 10000) 100) (/ (random 10000) 100)))))
           (properties . ((mmsi . ,(random 10000))
                          (name . "debug")
                          (sog . 5))))
         state))
  (loop))



$ time csi -s ./smallerror.scm -:g -:hm8M  > /tmp/csilog 2>&1

real	0m39.305s
user	0m39.157s
sys	0m0.087s

[klm@kth arp]$ tail /tmp/csilog  -n 30
[GC] stack	0x00007fffddc9b220	0xffffffffddc9b100	0x00007fffddd9b220
[GC]  from	0x00007fd8f132e010	0x00007fd8f1726790	0x00007fd8f172e010	0x00000000003f8780
[GC]    to	0x00007fd8f0bab010	0x00007fd8f0bab010	0x00007fd8f0fab010 
[GC] 0 locatives (from 32)
[GC] level  1	gcs(minor)  0	gcs(major)  4458
[GC] stack	0x00007fffddc9b220	0xffffffffddc9b120	0x00007fffddd9b220
[GC]  from	0x00007fd8f0bab010	0x00007fd8f0f623e8	0x00007fd8f0fab010	0x00000000003b73d8
[GC]    to	0x00007fd8f132e010	0x00007fd8f132e010	0x00007fd8f172e010 
[GC] 0 locatives (from 32)
[GC] (old) fromspace: 	start=0x00007fd8f0bab010, 	limit=0x00007fd8f0fab010
[GC] (old) tospace:   	start=0x00007fd8f132e010, 	limit=0x00007fd8f172e010
[panic] out of memory - heap full while resizing - execution terminated

...more...
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval>
<eval> 	<--

nevermind pasted by klm` on Fri Feb 5 12:28:59 2016

scratch the above comment! it's panicing because it's rightfully OOM when it can't store 10000 geojson objects in 8M heap.

good news though, we can strip nonblocking-input-ports and still reproduce it:

;;; running like this:
;;; [klm@kth arp]$ csi -s geojson-generator.scm | csi -s ./arp-boats.scm -:g -:hm8M 2>&1 | grep resize -C 5

(use cjson)

(define state '())

(define (geojson-mmsi geojson)
  (let ((mmsi (alist-ref 'mmsi (or (alist-ref 'properties geojson) '()))))
    (assert (number? mmsi))
    mmsi))

(define (prj-geojson geojson state)
  (assert (<= (length state) 20000))
  ;; set properties for mmsi key:
  (alist-update (geojson-mmsi geojson) ;; key (mmsi)
                geojson ;; value (geojson feature)
                state))

(define count 0)
(port-for-each
 (lambda (line)
   (let ((json (string->json line)))
     (set! count (add1 count))
     (set! state (prj-geojson json state))))
 read-line)



narrowing things down pasted by klm` on Fri Feb 5 12:53:25 2016

;;; running like this:
;;; ./arp-boats.scm -:g -:hm8M 2>&1 | grep resize -C 5

(define state '())

(let loop ()
  (set! state (alist-update (random 10000) (make-string 1000) state))
  (loop))

;; and you will *sometimes* see:
;; [GC] resized heap to 8388608 bytes
;; [GC] (new) fromspace: 	start=0x0000000001846560, 	limit=0x0000000001c46560
;; [GC] (new) tospace:   	start=0x0000000001046540, 	limit=0x0000000001446540
;; [GC] (old) fromspace: 	start=0x0000000001846560, 	limit=0x0000000001c46560
;; [GC] (old) tospace:   	start=0x0000000001046540, 	limit=0x0000000001446540
;; going on in a loop after about 4 seconds.

;; other times, you might see 
;;[panic] out of memory - heap full while resizing - 
;; execution terminated
;; and the program exiting (good thing, I suppose?)

no title pasted by klm` on Fri Feb 5 12:57:42 2016

the problem persists with 16M heap too:

$ csi -s ./arp-boats.scm -:g -:hm16M 2>&1 | grep --line-buffered resized | while read L ; do echo `date +%F_%T` "$L" ; done
2016-02-05_12:56:16 [GC] resized heap to 3145728 bytes
2016-02-05_12:56:16 [GC] resized heap to 6291456 bytes
2016-02-05_12:56:17 [GC] resized heap to 12583920 bytes
2016-02-05_12:56:22 [GC] resized heap to 16777216 bytes
2016-02-05_12:56:29 [GC] resized heap to 16777216 bytes
2016-02-05_12:56:29 [GC] resized heap to 16777216 bytes
2016-02-05_12:56:29 [GC] resized heap to 16777216 bytes
2016-02-05_12:56:29 [GC] resized heap to 16777216 bytes
... forever resizing

monitoring heap-usage in a separate thread added by klm` on Mon Feb 8 11:17:24 2016


;;; this is _very_ useful if you want to see if you're leaking memory somewhere:

(thread-start!
 (lambda ()
   (let loop ()
     (print "memory-statistics " (memory-statistics) "   (length state): " (length state))
     (flush-output)
     (thread-sleep! 1)
     (loop))))