Git Product home page Git Product logo

Comments (13)

bakpakin avatar bakpakin commented on September 21, 2024 3

True, there is some room for some more functionality in the ev library here - both the ability to Send interrupts to other threads as well as just call pthread_cancel on them. Unfortunately this has some issues with memory management so we may not support pthread_cancel directly

from spork.

pepe avatar pepe commented on September 21, 2024 2

We can have both implementations in the spork, as someone can use the current version.

from spork.

sogaiu avatar sogaiu commented on September 21, 2024 1

Tried it out a bit:

  (do
    (def ds @{})
    (timeit-loop [:repeat 100_000] :label
      (put ds :a 1))
    ds)
  # printed: label 0.008s, 0.08157µs/body
  # =>
  @{:a 1}

  (do
    (def ds @{})
    (timeit-loop [:repeat 100_000] :label
      (set (ds :a) 1))
    ds)
  # printed: label 0.007s, 0.07186µs/body
  # =>
  @{:a 1}

  (timeit-loop [:timeout 1] :label
    (get {:a 1} :a))
  # printed: label 1.000s, 0.06712µs/body
  # =>
  nil

Looks like it's working :)

seems like it could be avoided using an os/sleep in a separate thread?

I'm not sure, but may be at 0.03µs, it's better to keep the implementation simple at least initially?

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

Cleaned up slightly:

(defmacro timeit-loop
  ``Similar to `loop`, but outputs performance statistics after completion.``
  [head & body]
  (def tag "Elapsed time:")
  (with-syms [c head2 start elapsed per-body _]
    (def head2 @[;head])
    (when (def i (index-of :timeout head2))
      (array/insert head2 i _)
      (set (head2 (+ i 1)) :iterate)
      (set (head2 (+ i 2)) ~(< (- (os/clock) ,start) ,(in head2 (+ i 2)))))
    ~(do
       (var ,c 0)
       (def ,start (os/clock))
       (loop ,head2 (++ ,c) ,;body)
       (def ,elapsed (- (os/clock) ,start))
       (def ,per-body (/ ,elapsed ,c))
       (cond
         (< ,per-body 1e-3) (printf "%s %fs, %.4gµs/body" ,tag ,elapsed (* ,per-body 1_000_000))
         (< ,per-body 1) (printf "%s %fs, %.4gms/body" ,tag ,elapsed (* ,per-body 1_000))
         (printf "%s %fs, %.4gs/body" ,tag ,elapsed ,per-body)))))


(def ind (range 1000))
(timeit-loop [:timeout 2]
  (take -500 ind))
# ->
Elapsed time: 2.000049s, 3.275µs/body

Two things I'd like to modify:

  • add a :timeout verb to prematurely break after a given number of seconds has elapsed
  • make tag somehow configurable, as it is with timeit

I'm not quite sure what the best approach is to achieve either of these. Suggestions welcome.

from spork.

sogaiu avatar sogaiu commented on September 21, 2024

No good ideas about :timeout.

Some hacky ideas for tag:

  1. Dynamic variable
  2. Scan first part of body for a keyword to use as a tag
  3. Similar to previous idea, but use dictionary instead -- it can contain a key-value pair indicating a tag

For 2. and 3., having keywords or dictionaries at the beginning of a body of code usually doesn't mean anything (unless in the dictionary there is something side-effecty).

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

No good ideas about :timeout.

Patching it for an :iterate verb seems to work.

I suppose if the first form of the body is a bytes?, it could be assumed to be the tag?

from spork.

sogaiu avatar sogaiu commented on September 21, 2024

Patching it for an :iterate verb seems to work.

Nice.

I suppose if the first form of the body is a bytes?, it could be assumed to be the tag?

That sounds like it might work [1].

If you ever wanted to support more / other things, a struct (no point in it being a table I guess) could be checked for perhaps.


[1] This kind of approach has been working for me in other places. One example is for "tagging" jpm tasks. There I look for a keyword followed by a tuple -- after (task "name" [...]. timeit-loop's case is safer because you control it :)

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

That sounds like it might work [1].

I think it works great.

(defmacro timeit-loop
  ``Similar to `loop`, but outputs performance statistics after completion.
  Additionally defines a `:timeout` verb to iterate continuously for a given
  number of seconds. If the first form of `body` is a bytes, it will be taken
  as a custom tag.``
  [head & body]
  (var tag "Elapsed time:")
  (def head2 @[;head])
  (def body2 @[;body])
  (with-syms [c start elapsed per-body]
    (when (def i (index-of :timeout head2))
      (array/insert head2 i [])
      (set (head2 (+ i 1)) :iterate)
      (set (head2 (+ i 2)) ~(< (- (os/clock) ,start) ,(in head2 (+ i 2)))))
    (when (bytes? (get body2 0))
      (set tag (in body2 0))
      (array/remove body2 0))
    ~(do
       (var ,c 0)
       (def ,start (os/clock))
       (loop ,head2 (++ ,c) ,;body2)
       (def ,elapsed (- (os/clock) ,start))
       (def ,per-body (/ ,elapsed ,c))
       (cond
         (< ,per-body 1e-3) (printf "%s %.3fs, %.4gµs/body" ,tag ,elapsed (* ,per-body 1_000_000))
         (< ,per-body 1) (printf "%s %.3fs, %.4gms/body" ,tag ,elapsed (* ,per-body 1_000))
         (printf "%s %.3fs, %.4gs/body" ,tag ,elapsed ,per-body)))))

(timeit-loop [:repeat 200_000_000] ":repeat ")
(timeit-loop [:timeout 1] ":timeout")
# ->
:repeat  1.043s, 0.005214µs/body
:timeout 1.000s, 0.03572µs/body

About the :timeout, the os/clock adds about 0.03µs of overhead, which probably isn't a big deal for the purpose of comparison, but also seems like it could be avoided using an os/sleep in a separate thread?

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

I'm not sure, but may be at 0.03µs, it's better to keep the implementation simple at least initially?

Actually, ev/deadline or ev/with-deadline seem like they were intended for precisely this sort of thing. I can't figure out the proper usage, though.

(ev/with-deadline 1 (forever nil))

This never terminates.

from spork.

sogaiu avatar sogaiu commented on September 21, 2024

Similar situation here.

Replacing (forever nil) with (os/sleep 3) seems to terminate though not sure what the responsible mechanism is there.

Admittedly, not so helpful for the intended use-case.

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

This almost does the job:

(var c 0)
(def f (ev/spawn (forever (++ c))))
(os/sleep 1)
(ev/cancel f :timeout)

the counting var from f would need to be propagated somehow, though.

from spork.

bakpakin avatar bakpakin commented on September 21, 2024

Janet has a way to interrupt the interpreter, but it's not accessible from Janet, only from C with janet_interrupt. You could insert (ev/sleep 0) every turn of the loop but that would have unacceptable perf cost for timing.

Ideal we could spawn a new thread, sleep for some time, and then set the interrupt flag in the original interpreter.

from spork.

primo-ppcg avatar primo-ppcg commented on September 21, 2024

The task doesn't seem so complicated, though.

  1. Start a thread.
  2. Terminate it after n seconds.

Everything I tried either fails to halt the thread, or terminates with a seemingly unrecoverable error.

from spork.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.