performance measurements

Each table row shows performance measurements for this Clojure program with a particular command-line input value N.

 N  CPU secs Elapsed secs Memory KB Code B ≈ CPU Load
60,0007.363.44270,5161331  52% 68% 48% 44%
600,00023.1816.25412,4761331  37% 37% 34% 28%
6,000,000156.85134.78415,2481331  32% 30% 24% 25%

Read the ↓ make, command line, and program output logs to see how this program was run.

Read chameneos-redux benchmark to see what this program should do.

 notes

java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

Clojure 1.6

 chameneos-redux Clojure program source code

; The Computer Language Benchmarks Game
; http://benchmarksgame.alioth.debian.org/
;
; contributed by Kenneth Jonsson
;
; Each chameneos is its own agent and the agent state contains number
; of meetings, number of meetings with self and current color.
; The meeting point is implemented as a agent, where the state
; contains, among other things, number of meetings left to do.
;
; Build with
; $ java -Dclojure.compile.path=. -cp ${CLASSPATH} clojure.lang.Compile chameneosredux
;
; run with
; $ java -server -XX:+TieredCompilation -XX:+AggressiveOpts -cp ${CLASSPATH} chameneosredux 6000000
;
; where ${CLASSPATH} includes the current directory and the jar files
; for clojure core and clojure contrib
;

(ns chameneosredux (:gen-class))

(defn num->spell-out-str [n]
  "Converts a number to a string, ex 123 -> \" one two three\""
  (reduce (fn [s i] (str s " " (condp = i
                                        \0 "zero"
                                        \1 "one"
                                        \2 "two"
                                        \3 "three"
                                        \4 "four"
                                        \5 "five"
                                        \6 "six"
                                        \7 "seven"
                                        \8 "eight"
                                        \9 "nine")))
          ""
          (pr-str n)))

; Colors are defined as a map containing a string representation of
; the color and a function that knows how to complement itself with
; another color.
(declare *blue* *red* *yellow*)
(def *blue*   {:complement #(condp = %
                             *red*    *yellow*
                             *yellow* *red*
                             *blue*   *blue*)
               :str "blue"})
(def *red*    {:complement #(condp = %
                             *blue*   *yellow*
                             *yellow* *blue*
                             *red*    *red*)
               :str "red"})
(def *yellow* {:complement #(condp = %
                             *red*    *blue*
                             *blue*   *red*
                             *yellow* *yellow*)
               :str "yellow"})

(defn print-color-table []
  "Prints all possible color conversions to stdout"
  (let [colors [*blue* *red* *yellow*] ]
    (doseq [colPair (for [x colors y colors] [x y])]
      (let [[col1 col2] colPair
	    new-col ((:complement col1) col2)]
        (println (:str col1) "+" (:str col2) "->" (:str new-col)))))
  (println))


; Agent that prints the result, used to restore order between games
; running simultanious. Results will be printed in the order they
; where started with \"run-game\".
(def *in-order* (agent {:id 1}))

(defn print-result [s result]
  (if (nil? result)
    s
    (let [[id colors creatures] result]
      (if (< (:id s) id)
        (assoc s :results (sort (conj (:results s) result)))
        (if (nil? creatures)
          ; No more games are running, shutdown
          (shutdown-agents)
          (do
            ; Print starting colors
            (doseq [col colors]
              (print "" (:str col)))
            (println)
            ; Print number of meetings done by each creature
            (doseq [c creatures]
              (println (str (:meetings @c)
                            (num->spell-out-str (:met-self @c)))))
            ; Spell out the total number of meetings.
            (println (num->spell-out-str (reduce (fn [sum c]
                                                   (+ sum (:meetings @c)))
                                                 0
                                                 creatures)))
            (println)
            ; Check if there are more results to print
            (recur (assoc s
                     :id (inc (:id s))
                     :results (rest (:results s)))
                   (first (:results s)))))))))


; Functions run in the context of the agent assigned to the meeting
; place, ; i.e. *agent* is the agent for the meeting place.
(declare met-with)

(defn meet [m creature]
  "Meeting place is either empty and the creature must wait or a
   meeting takes place and the creatures leave"
  (if (zero? (:meetings-left m))
    ; No more meetings left
    m
    (if (nil? (:waiting m))
      ; No other creature here, need to wait
      (assoc m :waiting creature)
       ; Creature is here, lets meet. Each creature will update its
       ; own state in the context of its agent
      (let [new-ml (dec (:meetings-left m))
            waiting-creature (:waiting m)]
        (send creature
              met-with
              (:color @waiting-creature)
              (= creature waiting-creature)
              *agent*)
        (send waiting-creature
              met-with
              (:color @creature)
              (= creature waiting-creature)
              *agent*)
        (if (zero? new-ml)
          ; We are done, schedule a print of the results
          (send *in-order* print-result [(:id m) (:start-colors m) (:creatures m)]))
        (assoc m :meetings-left new-ml :waiting nil)))))


; Functions run in the context of the agent assigned to each creature
; i.e. *agent* is the agent for a chameneos.
(defn met-with [creature other-col met-self meeting-place]
  "Switch color based on the color of the creature met"
  (send meeting-place meet *agent*)
  {:meetings (inc (:meetings creature))
   :color ((:complement (:color creature)) other-col)
   :met-self (+ (:met-self creature) (if met-self 1 0))})


; Functions run in the main thread
(def *game-id* (atom 0))

(defn run-game [n & colors]
  "Runs a single meeting game, each game has its own set of agents for
   chameneos and the meeting place"
  (let [creatures (for [col colors] (agent {:color col
                                            :meetings 0
                                            :met-self 0}))
        meeting-place (agent {:id (swap! *game-id* inc)
                              :start-colors colors
                              :creatures creatures
                              :meetings-left n})]
    (doseq [creature creatures]
      (send meeting-place meet creature))))

(defn no-more-games []
  "No more games will be run, this process will be terminated when all
  games started with \"run-game\" has finished"
  (send *in-order* print-result [(swap! *game-id* inc) nil nil]))

(defn -main [& args]
  (let [num-meetings (if (empty? args)
                       0
                       (Integer/parseInt (first args)))]
    (print-color-table)
    (run-game num-meetings
	      *blue* *red* *yellow*)
    (run-game num-meetings
	      *blue* *red* *yellow* *red* *yellow* *blue* *red*
	      *yellow* *red* *blue*)
    (no-more-games)))

 make, command-line, and program output logs

Wed, 19 Nov 2014 18:05:18 GMT

MAKE:
mv chameneosredux.clojure chameneosredux.clj
/usr/local/src/jdk1.8.0_25/bin/java -Dclojure.compile.path=. -cp .:/usr/local/src/clojure/clojure-1.6.0.jar clojure.lang.Compile chameneosredux
Compiling chameneosredux to .
Warning: *blue* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *blue* or change the name. (chameneosredux.clj:42)
Warning: *red* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *red* or change the name. (chameneosredux.clj:42)
Warning: *yellow* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *yellow* or change the name. (chameneosredux.clj:42)
Warning: *blue* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *blue* or change the name. (chameneosredux.clj:43)
Warning: *red* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *red* or change the name. (chameneosredux.clj:48)
Warning: *yellow* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *yellow* or change the name. (chameneosredux.clj:53)
Warning: *in-order* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *in-order* or change the name. (chameneosredux.clj:72)
Warning: *game-id* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *game-id* or change the name. (chameneosredux.clj:149)
2.16s to complete and log all make actions

COMMAND LINE:
/usr/local/src/jdk1.8.0_25/bin/java -server -XX:+TieredCompilation -XX:+AggressiveOpts  -cp .:/usr/local/src/clojure/clojure-1.6.0.jar chameneosredux 6000000

PROGRAM OUTPUT:
blue + blue -> blue
blue + red -> yellow
blue + yellow -> red
red + blue -> yellow
red + red -> red
red + yellow -> blue
yellow + blue -> red
yellow + red -> blue
yellow + yellow -> yellow

 blue red yellow
4004644 zero
3985760 zero
4009596 zero
 one two zero zero zero zero zero zero

 blue red yellow red yellow blue red yellow red blue
1200362 zero
1199285 zero
1200000 zero
1199960 zero
1200465 zero
1200113 zero
1200325 zero
1199604 zero
1199947 zero
1199939 zero
 one two zero zero zero zero zero zero

Revised BSD license

  Home   Conclusions   License   Play