📄 latency.c
字号:
/* NOTE: copied from latency sampling demo */
/*
* Copyright (c) 1995,2000 TriMedia Technologies Inc.
*
* +------------------------------------------------------------------+
* | This software is furnished under a license and may only be used |
* | and copied in accordance with the terms and conditions of such |
* | a license and with the inclusion of this copyright notice. This |
* | software or any other copies of this software may not be provided|
* | or otherwise made available to any other person. The ownership |
* | and title of this software is not transferred. |
* | |
* | The information in this software is subject to change without |
* | any prior notice and should not be construed as a commitment by |
* | TriMedia Technologies. |
* | |
* | this code and information is provided "as is" without any |
* | warranty of any kind, either expressed or implied, including but |
* | not limited to the implied warranties of merchantability and/or |
* | fitness for any particular purpose. |
* +------------------------------------------------------------------+
*
* Module name : latency.c 1.8
*
* Last update : 17:07:14 - 00/06/16
*
* Description :
*
*
* Revision :
* Built for the TCS 1.1 release
*
*
*
* Overview:
* ========
*
* This is the source of a demonstration library which can be
* linked against an application to sample its interrupt latencies.
*
* A 'latency' of an interrupt is the difference in time between the
* moment at which the interrupt is asserted and the moment at which
* its handler starts executing. Any (noticeable) latency is
* caused by the application, by having disabled the particular
* interrupt.
*
* Longer latencies in an application may be harmful, since they
* reduce real time response. This may result in overrun errors
* of input devices, in which captured data is lost because the
* processor was notified to late to timely read it away and process
* it; or it may result in output device underrun errors in which
* no new output data has been made available in time because the
* processor has been too slow in reacting on a previous device
* notification.
*
* Depending on the characteristics of the application, either
* a worst case, or the average case interrupt latency is the issue:
* in a video application, an occasional `bad' latency might
* temporarily reduce the video quality, which need not be a problem.
* A disconnecting modem, even only occasionally, is next to
* unusable.
*
*
* Reasons for interrupt disabling:
* ===============================
*
* Clearing the IEN:
* ----------------
*
* Disabling of an interrupt may be achieved by clearing the IE bit in
* the PCSW. Massively disabling all interrupts in this way, and
* later enabling them again is the usual way to achieve without much
* overhead a critical section in which a device, or global data
* structure can be accessed without the danger of a task context
* switch or a new intervening interrupt.
* Two compiler- supported mechanisms provide an effect similar to
* clearing the IEN bit:
*
* 1) Defining an interupt handler as a `TCS_handler` (in contrast to
* a `TCS_interruptible_handler`). The generated code for such a
* handler clears the IEN at the start, to be enabled at the end
* of the handler.
* 2) Defining a function or handler as a 'TCS_atomic'. For these
* functions, the compiler will generate non-interruptible jumps
* (on the TM1, interrupts and exceptions are only served at
* 'interruptible jumps).
* NOTE that explicit use of non-interruptible jumps in handcoded
* assembly also locks out interrupts.
*
* As a general rule, applications should not run with a cleared IEN
* PCSW bit for more than 10 micro seconds. The IEN can be cleared,
* set and restored by means of functions intClearIEN, intSetIEN and
* intRestoreIEN from the tmInterrupts library.
*
* Changing the global interupt priority:
* -------------------------------------
*
* Although less common, interrupt disabling can also be achieved by
* raising the global interrupt priority to a value higher than the
* interrupt priority. This mechanism is generally used in interrupt
* handlers, to let serving not be disturbed by 'less urgent`
* interrupts, while still allowing 'more urgent' ones. So while the
* IEN is generally used to achieve atomicity, disabling based
* on interrupt priority is used to (temporarily) allocate processor
* cycles only to a certain minimal urgency. The global interrupt
* priority can be modified by means of a call to intSetPriority
* from the tmInterrupts library.
*
* Individual disabling:
* --------------------
*
* Interrupts can also be individually disabled. For instance, using
* a call to intInstanceSetup from the tmInterrupts library, interrupt
* intVIDEOIN can be individually disabled; regardless of its priority,
* and it has no effect on other interrupts.
*
*
* Sampling method used:
* ====================
*
* The latency sampler in this example records the interrupt latencies
* of a periodic interrupt whose handler runs at interrupt priority 0.
* Since it runs at the lowest interrupt priority, its latencies are
* always larger than or equal to those of any other interrupt which
* is not individually disabled. Because of this, the provided samples
* can be considered as lower bounds of the latencies over all interrupts
* which are not individually disabled; on the other hand, the samples
* can *not* be used for obtaining any latency information of interrupts
* which have been individually disabled.
*
* Sampling is timer based: a periodic interrupt is generated and
* the difference between timer elapse and actual invokation
* of its interrupt handler is measured and recorded. This means that
* this sampler can only be used when at least one of the three TM1
* timers is available for sample timing.
* The samples themselves are recorded in an array of buckets of which
* entry i contains the number of sampled latencies between i * 2^LOGS
* and (i+1) * 2^LOGS for 0<(i<NROF_BUCKETS-1). Entry NROF_BUCKETS-1
* contains the number of samples latencies larger than
* (NROF_BUCKETS-1) * 2^LOGS.
*
*
* Using the sampler:
* =================
*
* Sampling must be started by calling function init_latency. This
* function clears the bucket array, allocates a timer, and starts
* sampling. Upon successful initialisation, it returns True, False
* otherwise. Function term_latency stops sampling, frees the used timer,
* and prints the contents of all non- empty buckets to the standard
* output.
*
*
* Detection of latency violators:
* ==============================
*
* Upon any sampled latency larger than NROF_BUCKETS * 2^LOGS,
* the function LATENCY_VIOLATOR_DETECTED is called. This can be
* used to detect the part of the application which was responsible
* for this long latency, by placing a breakpoint in this function
* using tmdbg. When hitting this breakpoint, a stack traversal
* will reveal the function which performed a too late interrupt
* enable.
*
*
*
* Sample output:
* =============
*
* A sample output after a PSOS benchmark which in a loop
* invokes all pSOS functions to measure their performance
* is as follows (NROF_BUCKETS= 1000, LOGS=4, SAMPLE_PERIOD=500,
* host is Mac):
*
* 32 : 711
* 48 : 29
* 64 : 24
* 80 : 20
* 96 : 26
* 112 : 8
* 128 : 2
* 144 : 2
* 176 : 1
* 192 : 1
* 208 : 1
* 288 : 1
* 384 : 2
* 496 : 1
* 560 : 1
* 720 : 1
* 992 : 1
* 1248 : 1
*
* On the 80MHz processor used, this meant that the maximal
* latency measured was 15us, with an average latency below 1 us.
*
*/
/*----------------------------- includes ------------------------------------*/
#include <tm1/tmTimers.h>
#include <tm1/tmTimersmmio.h>
#include <tm1/mmio.h>
#include <stdio.h>
#include <stdlib.h>
/*------------------------- local definitions -------------------------------*/
#define NROF_BUCKETS 1000 /* number of sample buckets */
#define LOGS 4 /* binary logarithm of sample bucket size */
#define SAMPLE_PERIOD 1000 /* cycles */
static Int buckets[NROF_BUCKETS];
static Int sample_timer;
static Int last_tick;
/*------------------------- utility functions -------------------------------*/
LATENCY_VIOLATOR_DETECTED()
{
intClearIEN();
/* Place a breakpoint here */
intSetIEN();
}
static void
sampler(void)
{
#pragma TCS_handler
Int now = cycles();
Int sample_timer_value = timGetVALUE(sample_timer);
Int this_tick = now - sample_timer_value;
Int latency = now - last_tick - SAMPLE_PERIOD;
Int bucket_nr = latency >> LOGS;
last_tick = this_tick;
if (bucket_nr >= NROF_BUCKETS) {
buckets[NROF_BUCKETS - 1]++;
LATENCY_VIOLATOR_DETECTED();
}
else if (bucket_nr < 0) {
buckets[0]++;
}
else {
buckets[bucket_nr]++;
}
}
Bool
init_latency()
{
timInstanceSetup_t setup;
if (timOpen(&sample_timer) != TMLIBDEV_OK) {
return False;
}
else {
memset((Pointer) buckets, 0, sizeof (buckets));
last_tick = cycles();
setup.source = timCLOCK;
setup.prescale = 1;
setup.modulus = SAMPLE_PERIOD;
setup.running = True;
setup.handler = sampler;
setup.priority = intPRIO_0;
timInstanceSetup(sample_timer, &setup);
return True;
}
}
void
term_latency()
{
Int i;
timClose(sample_timer);
for (i = 0; i < NROF_BUCKETS; i++) {
if (buckets[i]) {
printf(" %7d : %7d\n", i << LOGS, buckets[i]);
}
}
}
#include "sys_conf.h"
main(Int argc, String argv[])
{
Int seconds = 10;
if (argc == 2) {
seconds = atoi(argv[1]);
}
else if (argc > 2) {
printf("Usage: latency [ nrof_seconds ]\n");
exit(-1);
}
if (!init_latency()) {
printf("Error: no available timer for sampling.\n");
exit(-1);
}
tm_wkafter(seconds * KC_TICKS2SEC);
term_latency();
exit(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -