source: umon/main/common/timestuff.c @ b987a75

Last change on this file since b987a75 was b987a75, checked in by Jarielle Catbagan <jcatbagan93@…>, on 06/19/15 at 21:32:43

Removed execution mode file attribute from all ASCII text files

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/**************************************************************************
2 *
3 * Copyright (c) 2013 Alcatel-Lucent
4 *
5 * Alcatel Lucent licenses this file to You under the Apache License,
6 * Version 2.0 (the "License"); you may not use this file except in
7 * compliance with the License.  A copy of the License is contained the
8 * file LICENSE at the top level of this repository.
9 * You may also obtain a copy of the License at:
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 **************************************************************************
20 *
21 * timestuff.c
22 *
23 * These functions support the monitor's ability to deal with elapsed
24 * time on targets with or without hardware-timer support.
25 *
26 * The INCLUDE_HWTMR definition in config.h determines which mode
27 * the timer will run in.
28 *
29 * The monitor does not require any hardware-assist for maintaining
30 * elapsed time.  With no hardware assist (INCLUDE_HWTMR set to 0),
31 * the value of LOOPS_PER_SECOND must be established in config.h, and
32 * can be calibrated using the '-c' option in the sleep command.  Even
33 * with this calibration the accuracy of this mechanism is limited;
34 * however, since there is no code in the monitor that really requires
35 * extremely accurate timing this may be ok.
36 *
37 * On the other hand, it is preferrable to have accuracy, so on targets
38 * that have a pollable clock,  the hooks can be put in place to allow
39 * that clock to be used as the hardware assist for the monitor's
40 * elapsed time measurements.  The INCLUDE_HWTMR is set to 1, and
41 * TIMER_TICKS_PER_MSEC defines the number of ticks of the timer that
42 * correspond to 1 millisecond of elapsed time.  The function target_timer()
43 * is assumed to be established and must return an unsigned long value
44 * that is the content of the polled hardware timer.
45 *
46 * Regardless of the hardware-assist or not, the following interface is
47 * used by the code in the monitor...
48 *
49 *      #include "timer.h"
50 *
51 *      struct elapsed_tmr tmr;
52 *
53 *      startElapsedTimer(&tmr,TIMEOUT):
54 *      do {
55 *              SOMETHING();
56 *      } while(!msecElapsed(&tmr));
57 *
58 * Refer to the functions startElapsedTimer() and msecElapsed() below for
59 * more details.
60 *
61 * Original author:     Ed Sutter (ed.sutter@alcatel-lucent.com)
62 *
63 */
64
65#include "config.h"
66#include "stddefs.h"
67#include "cli.h"
68#include "genlib.h"
69#include "ether.h"
70#include "timer.h"
71#include "cpuio.h"
72
73/* startElapsedTimer() & msecElapsed():
74 * The timer is started by loading the values timeout_low and timeout_high
75 * with the number of ticks that must elapse for the timer to expire.
76 *
77 * In the case of the non-hardware-assisted timer, the expiration count
78 * is based on the value of LoopsPerMillisecond (derived from the
79 * LOOPS_PER_SECOND definition in config.h).  Each time msecElapsed()
80 * is called the elapsed count is incremented until it exceeds the timeout
81 * timeout_low timeout_high values recorded by startElapsedTimer().
82 *
83 * The case of the hardware-assisted timer is similar except that now
84 * the number of ticks initialized in timeout_low and timeout_high are
85 * based on the tick rate of the hardware timer (TIMER_TICKS_PER_MSEC).
86 * This value is expected to be set in config.h.  Each time msecElapsed()
87 * is called, it samples the timer and adds to the running total of ticks
88 * until it matches or exceeds the timeout_low and timeout_high values.
89 *
90 * Notice that 64-bit values are used (high & low) because a 32-bit value
91 * isn't large enough to deal with the tick rates (per second) of various
92 * CPUs.
93 */
94void
95startElapsedTimer(struct elapsed_tmr *tmr, long milliseconds)
96{
97        unsigned long new_tm_low;
98        unsigned long stepmsecs, stepticks, remainder;
99
100#if INCLUDE_HWTMR
101        tmr->tmrflags = HWTMR_ENABLED;
102        tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC;
103#else
104        tmr->tmrflags = 0;
105        tmr->tpm = (unsigned long)LoopsPerMillisecond;
106#endif
107       
108        tmr->elapsed_low = 0;
109        tmr->elapsed_high = 0;
110        tmr->timeout_high = 0;
111        tmr->timeout_low = 0;
112       
113        /* Convert incoming timeout from a millisecond count to a
114         * tick count...
115         * Maximum number of milliseconds and ticks before 32-bit
116         * (tick counter) unsigned long overlaps
117         */
118        stepmsecs = 0xffffffff / tmr->tpm;
119        stepticks = stepmsecs * tmr->tpm;
120        remainder = (milliseconds % stepmsecs);
121
122        /* Take care of the step remainder
123         */
124        tmr->timeout_low = remainder * tmr->tpm;
125        milliseconds -= remainder;
126
127        for (;milliseconds; milliseconds -= stepmsecs) {
128                new_tm_low = tmr->timeout_low + stepticks;
129
130                if (new_tm_low < tmr->timeout_low)
131                        tmr->timeout_high++;
132                tmr->timeout_low = new_tm_low;
133        }
134       
135#if INCLUDE_HWTMR
136        tmr->tmrval = target_timer();
137#else
138        tmr->tmrval = 0;
139#endif
140
141}
142
143int
144msecElapsed(struct elapsed_tmr *tmr)
145{
146        ulong new_elapsed_low, new_tmrval, elapsed;
147
148        /* If timeout has already occurred, then we can assume that this
149         * function being called without a matching startElapsedTimer() call.
150         */
151        if (ELAPSED_TIMEOUT(tmr))
152                return(1);
153
154#if INCLUDE_HWTMR
155        new_tmrval = target_timer();
156#else
157        new_tmrval = tmr->tmrval + 1;
158#endif
159
160        /* Record how many ticks elapsed since the last call to msecElapsed
161         * and add that value to the total number of ticks that have elapsed.
162         */
163        elapsed = new_tmrval - tmr->tmrval;
164        new_elapsed_low = tmr->elapsed_low + elapsed;
165
166        if (new_elapsed_low < tmr->elapsed_low)
167                tmr->elapsed_high++;
168
169        /* If the total elapsed number of ticks exceeds the timeout number
170         * of ticks, then we can return 1 to indicate that the requested
171         * amount of time has elapsed.  Otherwise, we record the values and
172         * return 0.
173         */
174        if ((tmr->elapsed_high >= tmr->timeout_high) &&
175                (new_elapsed_low >= tmr->timeout_low)) {
176                tmr->tmrflags |= TIMEOUT_OCCURRED;
177                return(1);
178        }
179       
180        tmr->tmrval = new_tmrval;
181        tmr->elapsed_low = new_elapsed_low;
182        return(0);
183}
184
185/* msecRemainging():
186 * Used to query how many milliseconds were left (if any) in the timeout.
187 */
188ulong
189msecRemaining(struct elapsed_tmr *tmr)
190{
191        ulong high, low, msectot, leftover, divisor;
192
193        if (ELAPSED_TIMEOUT(tmr))
194                return(0);
195       
196        high = tmr->timeout_high - tmr->elapsed_high;
197        low = tmr->timeout_low - tmr->elapsed_low;
198
199        msectot = leftover = 0;
200
201#if INCLUDE_HWTMR
202        divisor = (ulong)TIMER_TICKS_PER_MSEC;
203#else
204        divisor = (ulong)LoopsPerMillisecond;
205#endif
206
207        while(1) {
208                while (low > divisor) {
209                        msectot++;
210                        low -= divisor;
211                }
212                leftover += low;
213                if (high == 0)
214                        break;
215                else {
216                        high--;
217                        low = 0xffffffff;
218                }
219        }
220
221        while(leftover > divisor) {
222                msectot++;
223                low -= divisor;
224        }
225        return(msectot);
226}
227
228/* monDelay():
229 * Delay for specified number of milliseconds.
230 * Refer to msecElapsed() description for a discussion on the
231 * accuracy of this delay.
232 */
233void
234monDelay(int milliseconds)
235{
236        struct elapsed_tmr tmr;
237
238        startElapsedTimer(&tmr,milliseconds);
239        while(!msecElapsed(&tmr)) {
240                WATCHDOG_MACRO;
241                pollethernet();
242        }
243}
244
245/* monTimer():
246 * Provide the API with the ability to start a millisecond-granularity
247 * timer with some countdown value, and poll it waiting for completion.
248 */
249int
250monTimer(int cmd, void *arg)
251{
252        int rc = 0;
253        struct elapsed_tmr *tmr = (struct elapsed_tmr *)arg;
254
255        switch(cmd) {
256                case TIMER_START:
257                        startElapsedTimer(tmr,tmr->start);
258                        break;
259                case TIMER_ELAPSED:
260                        msecElapsed(tmr);
261                        if (ELAPSED_TIMEOUT(tmr))
262                                rc = 1;
263                        break;
264                case TIMER_QUERY:
265#if INCLUDE_HWTMR
266                        tmr->tmrflags = HWTMR_ENABLED;
267                        tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC;
268                        tmr->currenttmrval = target_timer();
269#else
270                        tmr->tmrflags = 0;
271                        tmr->tpm = (unsigned long)LoopsPerMillisecond;
272                        tmr->currenttmrval = 0;
273#endif
274                        break;
275                default:
276                        rc = -1;
277                        break;
278        }
279        return(rc);
280}
281
282#if INCLUDE_TFSSCRIPT
283
284/* Sleep():
285 *      Simple delay loop accessible by the command line.
286 *      This loop count is dependent on the underlying hardware.
287 *      The LoopsPerMillisecond count is loaded with a default at startup, or
288 *  it can be calibrated by the user via the -c option.
289 *      Note that this LoopsPerMillisecond value is used in a few other places
290 *      in the monitor also for time-dependent stuff.
291 *      NOTES:
292 *      - This is obviously not real accurate (not intended to be), but allows the
293 *        monitor to be independent of the underlying hardware.
294 *      - The delay time is very dependent on ethernet activity, since the call
295 *        to pollethernet() part of the loop.
296 */
297
298
299char *SleepHelp[] = {
300        "Second or msec delay (not precise)",
301        "-[clmv:] {count}",
302#if INCLUDE_VERBOSEHELP
303        " -c  calibrate new LPS count",
304        " -l  store LPS count",
305        " -m  millisecond",
306        " -v {LPSvarname}",
307#endif
308        0,
309};
310
311int
312Sleep(int argc,char *argv[])
313{
314        int opt, calibrate, count, multiplier;
315
316        multiplier = 1000;
317        calibrate = 0;
318        while ((opt=getopt(argc,argv,"clmv:")) != -1) {
319                switch(opt) {
320                case 'c':
321                        calibrate = 2;
322                        break;
323                case 'l':
324                        calibrate = 1;
325                        break;
326                case 'm':
327                        multiplier = 1;
328                        break;
329                case 'v':
330                        shell_sprintf(optarg,"%d",LoopsPerMillisecond*1000);
331                        return(CMD_SUCCESS);
332                default:
333                        return(CMD_PARAM_ERROR);
334                }
335        }
336
337        /* If no args, just print the current LPS value and return... */
338        if (argc == 1) {
339#if INCLUDE_HWTMR
340                printf("Hardware-based timer, LPS not applicable\n");
341#else
342                printf("Current LPS = %ld\n",LoopsPerMillisecond * 1000);
343#endif
344                return(CMD_SUCCESS);
345        }
346
347        /* For calibration, take in the count on the command line, then use
348         * it to put out 5 dots dot at the rate of the loop to allow the user
349         * to adjust it to be about 1 second.
350         */
351        if (calibrate) {
352#if INCLUDE_HWTMR
353                printf("Hardware-based timer, doesn't calibrate\n");
354#else
355                long lps;
356
357                if (argc != optind+1)
358                        return(CMD_PARAM_ERROR);
359
360                printf("Current LPS: %ld\n",LoopsPerMillisecond * 1000);
361                lps = strtol(argv[optind],0,0);
362                LoopsPerMillisecond = lps/1000;
363                printf("New LPS: %ld%s\n",LoopsPerMillisecond * 1000,
364                        lps % 1000 ? " (truncated by 1000)" : "");
365
366                if (calibrate == 2) {
367                        count = 10;
368                        while(count-- > 0) {
369                                monDelay(1000);
370                                putstr(".\007");
371                        }
372                        putchar('\n');
373                }
374#endif
375                return(CMD_SUCCESS);
376        }
377
378        if (argc == optind)
379                count = 1;
380        else
381                count = strtol(argv[optind],(char **)0,0);
382
383        monDelay(count * multiplier);
384        return(CMD_SUCCESS);
385}
386#endif
Note: See TracBrowser for help on using the repository browser.