Skip to content

Commit

Permalink
Better docs and build, version 0.2
Browse files Browse the repository at this point in the history
Ocamldoc generation
Better doc in oclock.mli
Add a precision evaluation function in examples/realtime.ml
Add one example examples/getcputime.ml
Improve README
Use markdown in README
Add Findlib support
Minor fix in error handling in pthread_getcpuclockid
  • Loading branch information
polazarus committed Sep 17, 2010
1 parent 8668604 commit 3e8bab8
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 59 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -6,3 +6,4 @@
*.so
*.byte
*.opt
/doc/
5 changes: 5 additions & 0 deletions META
@@ -0,0 +1,5 @@
verson = "0.2"
description = "Oclock: Precise POSIX clock for Ocaml"
archive(byte) = "oclock.cma"
archive(native) = "oclock.cmxa"

36 changes: 25 additions & 11 deletions Makefile
Expand Up @@ -12,15 +12,16 @@
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

OCAMLC ?=ocamlc
OCAMLOPT ?=ocamlopt
OCAMLDEP ?=ocamldep
OCAMLC ?= ocamlc
OCAMLOPT ?= ocamlopt
OCAMLDEP ?= ocamldep
OCAMLFIND ?= $(shell which ocamlfind > /dev/null && echo ocamlfind)

OCAMLBFLAGS=
OCAMLOFLAGS=
OCAMLDEPFLAGS=
OCAMLBFLAGS ?=
OCAMLOFLAGS ?=
OCAMLDEPFLAGS ?=

OCAMLLIBDIR = $(shell ocamlc -where)
OCAMLLIBDIR ?= $(shell ocamlc -where)
INSTALL_DIR ?= $(OCAMLLIBDIR)/oclock
STUBLIBS_DIR ?= $(OCAMLLIBDIR)/stublibs

Expand Down Expand Up @@ -75,18 +76,31 @@ distclean: clean

# (Un)Install
install: all
ifdef OCAMLFIND
$(OCAMLFIND) install oclock oclock.cma oclock.cmxa liboclock.a oclock.cmi oclock.a META -dll dlloclock.so
else
install -d $(INSTALL_DIR)
install -t $(INSTALL_DIR) oclock.cma oclock.cmxa liboclock.a oclock.cmi oclock.a
install -t $(INSTALL_DIR) oclock.cma oclock.cmxa liboclock.a oclock.cmi oclock.a META
install -t $(STUBLIBS_DIR) dlloclock.so
endif

uninstall:
$(RM) $(INSTALL_DIR)/oclock.cma $(INSTALL_DIR)/oclock.cmxa $(INSTALL_DIR)/liboclock.a
rmdir $(INSTALL_DIR)
ifdef OCAMLFIND
$(OCAMLFIND) remove oclock
else
$(RM) -r $(INSTALL_DIR)
$(RM) $(STUBLIBS_DIR)/dlloclock.so
endif

# Documentation

doc:
mkdir -p doc
ocamldoc -d doc -html -d doc *.mli

# Examples
test examples: all
$(MAKE) -C examples

# Phony targets
.PHONY: install clean distclean all test
.PHONY: install clean distclean all test examples byte native doc
22 changes: 0 additions & 22 deletions README

This file was deleted.

1 change: 1 addition & 0 deletions README
61 changes: 61 additions & 0 deletions README.markdown
@@ -0,0 +1,61 @@
Oclock: precise POSIX clock for OCaml

Mickaël Delahaye

This module give access to the `clock_gettime (2)` family of functions to Ocaml
programs.

Requirements
============

Just the usual suspects: GNU Make, GCC, OCaml, and optionally Findlib (i.e.,
ocamlfind).

Installation
============

$ make
Build the library

# make install
Install the library in the standard ocaml directory

Usage
=====

Manually:
ocamlc -I +oclock oclock.cma ...
ocamlopt -I +oclock oclock.cmxa ...

Or with ocamlfind:
ocamlfind ocamlc -package oclock ...
ocamlfind ocamlopt -package oclock ...

Documentation
=============

To build the API documentation in HTML, use:
$ make doc
Then, open `doc/index.html` with your favorite browser.

Two examples are also provided in `examples`:

* _getcputime_ gets the CPU-time consumed by a process given by its PID.
* _realtime_ gets the real time since the Epoch, and evaluates the clock
precision.

License
=======
Copyright (c) 2010, Mickaël Delahaye <mickael.delahaye@gmail.com>

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
2 changes: 1 addition & 1 deletion examples/Makefile
Expand Up @@ -4,7 +4,7 @@ OCAMLOPT ?= ocamlopt
OCAMLC += -I +oclock
OCAMLOPT += -I +oclock

EXAMPLES=realtime
EXAMPLES=realtime getcputime

all: $(EXAMPLES:%=%.byte) $(EXAMPLES:%=%.opt)

Expand Down
19 changes: 19 additions & 0 deletions examples/getcputime.ml
@@ -0,0 +1,19 @@
(** Example of CPU-time measurement with Oclock *)

let rec loop () =
Printf.printf "PID? ";
try
let pid = read_int () in
begin try
let clk = Oclock.getcpuclockid pid in
let time = Oclock.gettime clk in
Printf.printf "The process %d used %Ld ns of CPU time up until now.\n\n" pid time;
with Invalid_argument s | Failure s ->
Printf.printf "Error: %s\n" s;
end;
loop ();
with End_of_file ->
Printf.printf "Bye!\n"

let () =
loop ()
41 changes: 37 additions & 4 deletions examples/realtime.ml
@@ -1,6 +1,39 @@
open Oclock
(** Example of realtime measurement with Oclock *)

(** Experimentally estimates the precision of a clock by observing gaps between
[num] successive measures (by default 100000).
Returns the observed (arithmetic) mean, the standard deviation, the minimal
value and the maximal value.
*)
let measure_precision ?(num=100000) clkid =
let t () = Oclock.gettime clkid in
let measures = Array.make num 0L in
for i = 0 to num - 1 do
measures.(i) <- t ();
done;
let last = ref measures.(0) in
let nb_diffs = ref 0 in
let diffs = ref [] in
for i = 1 to num - 1 do
if measures.(i) <> !last then begin
incr nb_diffs;
diffs := Int64.to_float (Int64.sub measures.(i) !last) :: !diffs;
last := measures.(i);
end
done;
let n = float_of_int !nb_diffs in
let mean = (List.fold_left (+.) 0.0 !diffs) /. n in
let var = (List.fold_left (fun acc e -> (e -. mean) ** 2.0 +. acc) 0.0 !diffs) /. n in
let min = List.fold_left min max_float !diffs in
let max = List.fold_left max min_float !diffs in
let stddev = var ** 0.5 in
mean, stddev, min, max

(** Gets time since Epoch and evaluates the precision of the clock *)
let () =
let nsecs = gettime realtime in
let res = getres realtime in
Printf.printf "%Ld ns (resolution %Ld ns)\n" nsecs res;
let nsecs = Oclock.gettime Oclock.realtime in
let res = Oclock.getres Oclock.realtime in
Printf.printf "%Ld ns since the Epock (resolution %Ld ns)\n" nsecs res;

let prec, precsv, max, min = measure_precision Oclock.realtime in
Printf.printf "Precision evaluation\n Mean: %10.2f ns\n Sdev: %10.2f ns\n Min: %10.2f ns\n Max: %10.2f ns\n" prec precsv min max
62 changes: 47 additions & 15 deletions oclock.mli
Expand Up @@ -15,42 +15,74 @@ THIS SOFTWARE.
*)

(**
OClock: precise time under POSIX
Oclock: precise POSIX clock for OCaml
A module to get more precise time under POSIX systems using clock_gettime(2).
This module give access to the [clock_gettime (2)] family of functions to
Ocaml programs.
If this module allows to access time of real- or CPU-time clocks in
nanoseconds, the actual precision of the clocks might be much coarser.
Also, the resolution of a clock, {!getres} should indicate the period of the
timer used for this clock, but the actual precision of the clock greatly
depends on the CPU (watch out for frequency scaling!) and its time source.
You can estimate the precision available on your platform with the shipped
example [examples/realtime].
*)

(** Clock identifier type *)
type clockid = int

(**Some clock identifiers *)
(** {2 Clock access } *)

(** Gets the clock's resolution in nanoseconds.*)
external getres : clockid -> int64 = "oclock_getres"

(** Gets the clock's time in nanoseconds. *)
external gettime : clockid -> int64 = "oclock_gettime"

(** Sets the clock's time in nanoseconds. *)
external settime : clockid -> int64 -> unit = "oclock_settime"

(** The three above functions raise [Invalid_argument] if the clock identifier
is not supported, and a [Failure] if the call fails for any ohter reason
(including permission problems). *)

(** {2 Clock identifiers } *)

(** {3 Current process/thread's clock identifiers } *)

(** Realtime (always valid) *)
val realtime : clockid

(** Monotonic (not subject to system time change) *)
val monotonic : clockid

(** Process CPU time *)
(** Current process CPU-time clock *)
val process_cputime : clockid

(** Thread CPU time *)
(** Current thread CPU-time clock *)
val thread_cputime : clockid

(** Another monotonic clock (not always present, since Linux 2.6.28; Linux-specific), not subject to NTP adjustements *)
(** Another monotonic clock (not always present, since Linux 2.6.28;
Linux-specific), not subject to NTP adjustements *)
val monotonic_raw : clockid

(** Get the clock's resolution in nanoseconds*)
external getres : clockid -> Int64.t = "oclock_getres"

(** Get the clock's time in nanoseconds *)
external gettime : clockid -> Int64.t = "oclock_gettime"
(** {3 Remote clock identifier } *)

(** Set the clock's time in nanoseconds *)
external settime : clockid -> Int64.t -> unit = "oclock_settime"
(** Gets the CPU-time clock identifier of a process (given its PID).
(** Get the clock identifier of a process (given its PID) *)
Raises an [Invalid_argument] exception if the provided integer is not a valid
PID, and a [Failure] if the calls fails for any other reason (including
permission problems).
*)
external getcpuclockid : int -> clockid = "oclock_getcpuclockid"

(** Get the clock identifier of a thread (given its pthread identifier) *)
(** Gets the CPU-time clock identifier of a thread given its pthread identifier,
as returned by [Thread.id] (but only if you use real POSIX threads [-thread]
and not VM threads [-vmthread]).
Raises an [Invalid_argument] exception if the provided integer is not a valid
thread identifier, and a [Failure] if the calls fails for any other reason
(including permission problems).
*)
external pthread_getcpuclockid : int -> clockid = "oclock_pthread_getcpuclockid"
15 changes: 9 additions & 6 deletions oclock_stubs.c
Expand Up @@ -116,13 +116,15 @@ CAMLprim value oclock_getcpuclockid(value vpid) {
if (clock_getcpuclockid(pid, &clkid) != 0) {
switch (errno) {
case ENOSYS:
/* not supported clock id */
/* "The kernel does not support obtaining the per-process CPU-time
clock of another process, and pid does not specify the calling
process" */
caml_failwith ("unsupported feature");
case EPERM: /* the user doesnt have the permission */
case EPERM: /* "The caller does not have the permission (...)" */
caml_failwith ("invalid permission");
case ESRCH: /* should be this one */
case EINVAL:
case ESPIPE: /* my linux send that one*/
case ESPIPE: /* my linux send this one */
caml_invalid_argument ("invalid pid");
default:
caml_failwith ("unknown failure");
Expand All @@ -141,14 +143,15 @@ CAMLprim value oclock_pthread_getcpuclockid(value vpid) {
if (pthread_getcpuclockid(pid, &clkid) != 0) {
perror(NULL);
switch (errno) {
case ENOSYS:
/* not supported clkid */
case ENOENT:
/* "Per-thread CPU time clocks are not supported by the system." */
caml_failwith ("unsupported feature");
case EPERM: /* dont have the perm */
caml_failwith ("invalid permission");
case ESRCH:
case ESRCH: /* should be this one */
case EINVAL:
case ESPIPE:
/* No thread with the ID thread could be found. */
caml_invalid_argument ("invalid pid");
default:
caml_failwith ("unknown failure");
Expand Down

0 comments on commit 3e8bab8

Please sign in to comment.