# Timing

When running statements within Magma in serial mode only, using the CPU time to measure the time taken between one or more statements is reasonable and accurate. In particular, one can: (1) use the `time` statement; (2) call the function `Cputime()` which returns the total CPU time (in seconds) taken by Magma since startup; (3) call the function `Cputime(T)` to give the CPU time (in seconds) taken since the variable `T` was last set to `Cputime()`.

However, when parallelism is used with multiple threads and/or distributed computation, the CPU time is not useful as a measure of the time taken, since this the value which the kernel yields for this typically includes the sum of the CPU time taken by all threads together with extra overhead in the kernel handling, and this number can be skewed even more if hyperthreading is present. So the real (wall-clock) time taken is usually not related to the CPU time divided by the total number of threads in any useful or accurate way. Also, in the distributed case, the CPU time can only refer to threads running on the master node, and not on worker nodes.

Consequently, the real (wall-clock) time taken by one or more statements in Magma is the best way to measure the time taken when parallelism is present. One way of obtaining this information is to call the function `Realtime(T)` to give the real time taken (in seconds) since `T` was last set to `Realtime()`. But it is easier just to use the `time` statement or the `Time` function, since these give useful timing information no matter whether serial or parallelism is present or not in any computation. These can be used as follows:

**(i)**
If `time` is placed before a statement and a multi-threaded/distributed algorithm is **not** used within the executed statement, then the CPU time alone is printed.

**(ii)**
If `time` is placed before a statement and a multi-threaded/distributed algorithm **is** used within the executed statement while the real time $r$ taken is less than the CPU time $c$ taken, then the time printed is $r$, and the tag `[r]` is appended (to indicate that the time printed is a real time); otherwise the CPU time $c$ is printed. So one can know whether a multi-threaded/distributed algorithm has been used within the executed statement: that is the case if and only if the tag `[r]` is printed.

**(iii)**
The verbose time statement `vtime` has the same behaviour as `time` in the above two cases.

**(iiv)**
The function `Time` is used in a similar way to `Cputime` and `Realtime`, while selecting their behaviour depending on whether parallelism is used: after setting a variable such as $T$ to `Time()`, then after a series of statements, one can print the value `Time(T)` (which is always a string) to give the lapsed time since $T$ was assigned. Just as for the `time` statement above, the tag `[r]` is added if and only if the real time is used in the second call to `Time`. So the presence of that tag indicates that at least one multi-threaded/distributed algorithm has been used between the calls to `Time`, while the absence of the tag indicates that no parallelism was used and the CPU time is returned by the `Time` function.

## `Example: Time1 (ex-0cea74)`

A simple example of the use of `time` and `Time` is the following.

```magma
> SetNthreads(1); // SERIAL (NO PARALLELISM)
> X := Random(MatrixRing(GF(5), 10000));
> time P := X*X; // serial only, so prints CPU time (seconds)
Time: 4.060
> T := Time(); P := X*X; Time(T); // same as what time statement prints
4.060

```

```magma
> SetNthreads(8); // PARALLEL (8 POSIX THREADS)
> time P := X*X;  // parallel, so real time shown by [r] (seconds)
Time: 1.050[r]
> T := Time(); P := X*X; Time(T); // same as what time statement prints
1.050[r]

```
