# Arithmetic function 'cputime' resolution

**URL:** <https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560>\
**Category:** Predicate\
**Created:** [June 28, 2022, 8:10pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560 "2022-06-28T20:10:38Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [June 28, 2022, 8:10pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/1 "2022-06-28T20:10:38Z")

</div>

On MacOS, the resolution of function `cputime` appears to 1 microsecond. Is this generally guaranteed or is it platform dependent?

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [June 29, 2022, 4:01am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/2 "2022-06-29T04:01:09Z")

</div>

The arithmetic function `cputime` is new for me. Thanks. Once I wrote my own `cputime` below, though I never met a chance to measure for a serious case. It displayed long digits, which I thought the resolution is fine enough (Intel macOS Monterey).

```prolog
:- meta_predicate cputime(?, 0, ?).
%
cputime(N, G, T):- writeln("Running pac runtime library cputime/3... "),
				   cputime(N, G, 0.00, T).
%
cputime(0, _G, T, T).
cputime(N, G, T, T0):- N0 is N - 1,
						cputime_for_step(G, S),
						T1 is T + S,
						cputime(N0, G, T1, T0).
%
cputime_for_step(G, T):-
	statistics(cputime, T0),
	call(G),
	statistics(cputime, T1),
	T is T1-T0.

```

Another simple version cputime.

```prolog
%
cputime:- statistics(cputime, T), b_setval(cputime, T).
cputime(T):- statistics(cputime, Stop), b_getval(cputime, Start), T is Stop - Start.

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [June 29, 2022, 7:28am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/3 "2022-06-29T07:28:26Z")

</div>

> [@ridgeworks](#):
>
> function `cputime` appears to 1 microsecond. Is this generally guaranteed or is it platform dependent?

Well, one needs the OS to get the CPU time 🙂 I don’t know. Roughly there are two interfaces for most OSes, an old one that gets these statistics in terms of the scheduler frequency and a new one that typically allows querying at nanosecond resolution. If possible we use the new interface 🙂

> [@kuniaki.mukai](#):
>
> The arithmetic function `cputime` is new for me

Its an old thing that came with C-Prolog compatibility 🙂 I’d use statistics/2, which is more widely supported. Unfortunately the details differ. SWI-Prolog reports in seconds as a float, many systems report as integer in milliseconds.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [June 29, 2022, 2:36pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/4 "2022-06-29T14:36:20Z")

</div>

So `cputime` isn’t even consistent across Prolog systems, let alone OS’s; good to know.

> [@jan](#):
>
> a new one that typically allows querying at nanosecond resolution. If possible we use the new interface

`statistics/2` similarly seems to provide microsecond resolution; on MacOS:

```prolog
?- statistics(cputime,T0),statistics(cputime,T1).
T0 = 27.036738,
T1 = 27.036741.

```

Is this guaranteed on all supported platforms?

Should I assume the nanosecond time isn’t directly accessible and may not be supported on all platforms?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [June 29, 2022, 7:08pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/5 "2022-06-29T19:08:52Z")

</div>

> [@ridgeworks](#):
>
> Is this guaranteed on all supported platforms?

I don’t know. The border of “supported” is not that clear. SWI-Prolog has binary releases for Ubuntu, MacOS and Windows, so if anything goes wrong on any of these it is typically fixed before releasing. On other platforms we depend on people sending bug reports or pull requests. SWI-Prolog is supposed to work on anything that provides a C compiler that conforms to the C11 standard and has at least a basic POSIX compliant OS interface.

> [@ridgeworks](#):
>
> Should I assume the nanosecond time isn’t directly accessible and may not be supported on all platforms?

The clock API (except for Windows) relies on clock\_gettime() on most systems (with fallback to older standards). The `struct timespec` provides nanoseconds which are translated to a C double. Possibly we should expose clock\_getres(), which provides the resolution provided by the OS/hardware?

Why do you care about this level of detail?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [June 29, 2022, 7:33pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/6 "2022-06-29T19:33:53Z")

</div>

> [@ridgeworks](#):
>
> So `cputime` isn’t even consistent across Prolog systems, let alone OS’s; good to know.

The code is here: [function CpuTime in pl-os.c](https://github.com/SWI-Prolog/swipl-devel/blob/ea9483afdfc640276dedaf3d3daebb696d8537ef/src/os/pl-os.c#L248)

The `timespec` structure gives nanosecond time stamps, but actual accuracy would depend on the underlying CPU.

On my Linux system (Chromebook, Debian), all three of these are defined:  
HAVE\_CLOCK\_GETTIME  
CLOCK\_PROCESS\_CPUTIME\_ID  
HAVE\_TIMES

If you can’t figure out what’s defined by looking at the cmake files (and I couldn’t), just add this to pl-os.c and rebuild:

```C
#if defined(HAVE_CLOCK_GETTIME)
#warning yes: HAVE_CLOCK_GETTIME
#endif
#if defined(CLOCK_PROCESS_CPUTIME_ID)
#warning yes: CLOCK_PROCESS_CPUTIME_ID
#endif
#if defined(HAVE_TIMES)
#warning yes: HAVE_TIMES
#endif

```

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [June 29, 2022, 8:42pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/7 "2022-06-29T20:42:26Z")

</div>

> [@jan](#):
>
> Why do you care about this level of detail?

I’ve been wondering whether the system clock can be used to generate unique timestamps, i.e., two successive calls to `cputime` (or some available alternative) would generate two different values on all platforms of “interest” (subjective, I know). I really don’t care about the actual values or what they represent; just that they’re monotonically increasing.

The answer seems to be no.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [June 29, 2022, 10:53pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/8 "2022-06-29T22:53:31Z")

</div>

> [@jan](#):
>
> Possibly we should expose clock\_getres(), which provides the resolution provided by the OS/hardware?

It’s only a few lines of code, so it seems useful … the result I get is 1nsec on both an AMD CPU and an Intel CPU.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [June 30, 2022, 2:51am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/9 "2022-06-30T02:51:13Z")

</div>

> [@peter.ludemann](#):
>
> It’s only a few lines of code, so it seems useful … the result I get is 1nsec on both an AMD CPU and an Intel CPU.

I wouldn’t recommend doing anything based on my input. `cputime` was an option I was considering and I was just curious. Using a `random_float` is more than good enough for what I need.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [June 30, 2022, 6:26am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/10 "2022-06-30T06:26:05Z")

</div>

> [@ridgeworks](#):
>
> I wouldn’t recommend doing anything based on my input.

Too late. [ENHANCED: added cputime\_resolution to is/2 by kamahen · Pull Request #1003 · SWI-Prolog/swipl-devel · GitHub](https://github.com/SWI-Prolog/swipl-devel/pull/1003)  
Unless @jan decides it’s a bad idea.  
Anyway, Python has it as part of its library: `time.clock_getres`(_clk\_id_), so that’s another vote for exposing `clock_getres()`.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [June 30, 2022, 7:28am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/11 "2022-06-30T07:28:01Z")

</div>

> [@ridgeworks](#):
>
> I really don’t care about the actual values or what they represent; just that they’re monotonically increasing.

Use statistics(inferences, Count). See statistics/2 (doesn’t show in the manual right now due to a conflict about section identifiers in the manual. Fixed the sources).

> [@peter.ludemann](#):
>
> It’s only a few lines of code, so it seems useful … the result I get is 1nsec on both an AMD CPU and an Intel CPU.

> [@peter.ludemann](#):
>
> Unless @jan decides it’s a bad idea.

It is surely a bad idea to add it as an arithmetic function. `cputime` is already something that just got there for compatibility long time ago. I think the most Prolog natural way would be to make it a Prolog flag, possibly an additional key to statistics/2. I don’t see enough reason to add it anyway. Surely we would need an alternative implementation for Windows and quite likely this will break several other OSes. I don’t think it is important enough to go through the portability trouble and actually I think it isn’t worth the lines of code to implement and document it.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [June 30, 2022, 12:49pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/12 "2022-06-30T12:49:05Z")

</div>

> [@jan](#):
>
> Use statistics(inferences, Count).

Perfect. I just didn’t think of using `statistics` for this purpose.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [June 30, 2022, 1:06pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/13 "2022-06-30T13:06:58Z")

</div>

No clue why you need this. It might be relevant to point at the notion of a _generation_ counter that is associated with the (predicate) database. That allows querying `last_modified_generation` on predicates and modules using predicate\_property/2 and module\_property/2. The global current generation is not accessible (but can be added if there is a good use case).

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [July 4, 2022, 1:46am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/14 "2022-07-04T01:46:27Z")

</div>

> [@jan](#):
>
> No clue why you need this.

Motivated by this thread: [Different results when using library(simplex) or R-package lpSolve / lpSolveAPI - #6 by ridgeworks](https://swi-prolog.discourse.group/t/different-results-when-using-library-simplex-or-r-package-lpsolve-lpsolveapi/5545/6)  
I’ve been looking at how to use `library(simplex)` in a CLP framework, the main issue being there’s an API mismatch. One of the main issues is that variables within a CLP system are represented by attributed variables while variables in `simplex` constraints are represented by atoms or compound terms, w.g., `x` or `x(0)`. In building a CLP friendly wrapper for `library(simplex)`, I wanted a light weight mechanism to associate a name with a CLP variable for relatively short period of time.

The first prototype used:

```prolog
simplex_var_(V,var(Vstr)) :- term_string(V,Vstr).

```

This looks up a variable name usable by `simplex` given a constrained variable `V`. `Vstr` is the “address” of the variable `V` converted to a string so it will be unique for any variable of interest. But it’s potentially not safe due to variable relocation during garbage collection. And it’s unlikely to be the most performant solution based on a simple benchmark.

A better approach is to use an attribute to store a unique ID of some kind. Using the cputime (a monotonically increasing value) was the first stab but appears to have platform dependancies and will probably start to fail at microsecond resolution (two successive queries may yield the same value). Using the inference counter neatly solves this problem. So the code becomes:

```prolog
simplex_var_(V,SV) :- 
	(get_attr(V,clpBNR_toolkit,SV)
	 -> true
	 ; statistics(inferences,Vname), SV = var(Vname), put_attr(V,clpBNR_toolkit,SV)
	).
		 
attr_unify_hook(var(_),_). % unification always does nothing and succeeds

```

This works quite nicely and is 10 times faster than a `term_string` based implementation.

Using the new clpBNR wrapper module for Example 2 from [`library(simplex)`](https://www.swi-prolog.org/pldoc/man?section=simplex):

```prolog
?- X1::real(0,1), X2::real(0,2), lin_maximize(7*X1+4*X2,{6*X1+4*X2=<8},Value).
X1 = 1,
X2 = 1r2,
Value = 9.

?- X1::integer(0,1), X2::integer(0,2), lin_maximize(7*X1+4*X2,{6*X1+4*X2=<8},Value).
X1 = 0,
X2 = 2,
Value = 8.

```

The new variable name attribute is removed before the completion of `lin_minimize/3` so there’s no lingering effects.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 4, 2022, 2:15am UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/15 "2022-07-04T02:15:21Z")

</div>

> [@ridgeworks](#):
>
> store a unique ID of some kind

gensym/2 ?  
(whose document also says: uuid/1, term\_hash/2, variant\_sha1/2 may be used to generate various unique or content-based identifiers safely.)

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [July 4, 2022, 2:25pm UTC](https://swi-prolog.discourse.group/t/arithmetic-function-cputime-resolution/5560/16 "2022-07-04T14:25:39Z")

</div>

Yes `gensym` or `uuid` could be used as well although they aren’t as time efficient as `statistics(inferences,ID)`. They also result in creation of new (very temporary) atoms which can be avoided using `statistics `.
