Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Basic stop-watch implementation.
0003  *
0004  * @file nstopwatch.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <memory.h>
0039 
0040 #include <ndrx_config.h>
0041 #include <sys_unix.h>
0042 #include <ndrstandard.h>
0043 #include <nstopwatch.h>
0044 #include "ndebug.h"
0045 #include <time.h>
0046 /*---------------------------Externs------------------------------------*/
0047 /*---------------------------Macros-------------------------------------*/
0048 /*---------------------------Enums--------------------------------------*/
0049 /*---------------------------Typedefs-----------------------------------*/
0050 /*---------------------------Globals------------------------------------*/
0051 /*---------------------------Statics------------------------------------*/
0052 /*---------------------------Prototypes---------------------------------*/
0053 
0054 /**
0055  * Decode time in human readable form.
0056  * Return only major units.
0057  * @param t
0058  * @param slot
0059  * @return 
0060  */
0061 expublic char *ndrx_decode_msec(long t, int slot, int level, int levels)
0062 {
0063     static char text[20][128];
0064     char tmp[128];
0065     long next_t=0;
0066 #define DEC_SECOND      ((long)1000)
0067 #define DEC_MINUTE      ((long)1000*60)
0068 #define DEC_HOUR        ((long)1000*60*60)
0069 #define DEC_DAY         ((long)1000*60*60*24)
0070 #define DEC_WEEK        ((long)1000*60*60*24*7)
0071 #define DEC_MONTH       ((long long)1000*60*60*24*7*4)
0072 #define DEC_YEAR        ((long long)1000*60*60*24*365)
0073 #define DEC_MILLENIUM     ((long long)1000*60*60*24*365*1000)
0074     
0075     level++;
0076     
0077     if ((double)t/DEC_SECOND < 1.0) /* Less that second */
0078     {
0079         snprintf(tmp, sizeof(tmp), "%ldms", t);
0080     }
0081     else if ((double)t/DEC_MINUTE < 1.0) /* less than minute */
0082     {
0083         snprintf(tmp, sizeof(tmp), "%lds", t/DEC_SECOND);
0084         
0085         if (level<levels)
0086             next_t = t%DEC_SECOND;
0087     }
0088     else if ((double)t/DEC_HOUR < 1.0) /* less that minute */
0089     {
0090         snprintf(tmp, sizeof(tmp), "%ldm", t/DEC_MINUTE);
0091         
0092         if (level<levels)
0093             next_t = t%DEC_MINUTE;
0094     }
0095     else if ((double)t/DEC_DAY < 1.0) /* less than hour */
0096     {
0097         snprintf(tmp, sizeof(tmp), "%ldh", t/DEC_HOUR);
0098         
0099         if (level<levels)
0100             next_t = t%DEC_HOUR;
0101     }
0102     /* Days */
0103     else if ((double)t/DEC_WEEK < 1.0) /* Less that week */
0104     {
0105         snprintf(tmp, sizeof(tmp), "%ldd", t/DEC_DAY);
0106         
0107         if (level<levels)
0108             next_t = t%DEC_DAY;
0109     }
0110     else if ((double)t/DEC_MONTH < 1.0) /* less than month */
0111     {
0112         snprintf(tmp, sizeof(tmp), "%ldw", t/DEC_WEEK);
0113         
0114         if (level<levels)
0115             next_t = t%DEC_WEEK;
0116     }
0117     else if ((double)t/DEC_YEAR < 1.0) /* less than year */
0118     {
0119         snprintf(tmp, sizeof(tmp), "%lldM", t/DEC_MONTH);
0120         
0121         if (level<levels)
0122             next_t = t%DEC_MONTH;
0123     }
0124     else if ((double)t/DEC_MILLENIUM < 1.0) /* less than 1000 years */
0125     {
0126         snprintf(tmp, sizeof(tmp), "%lldY", t/DEC_YEAR);
0127         
0128         if (level<levels)
0129             next_t = t%DEC_YEAR;
0130     }
0131     
0132     if (level==1)
0133         strcpy(text[slot], tmp);
0134     else
0135         strcat(text[slot], tmp);
0136     
0137     if (next_t)
0138         ndrx_decode_msec(next_t, slot, level, levels);
0139     
0140     return text[slot];
0141 }
0142 
0143 /**
0144  * Decode timer.
0145  * @param timer
0146  * @param slot
0147  * @return 
0148  */
0149 expublic char *ndrx_stopwatch_decode(ndrx_stopwatch_t *timer, int slot)
0150 {
0151     static char *na="N/A";
0152     
0153     if (NULL==timer || 0==timer->t.tv_sec)
0154     {
0155         return na;
0156     }
0157     
0158     return ndrx_decode_msec(ndrx_stopwatch_get_delta(timer), slot, 0, 2);
0159 }
0160 
0161 /**
0162  * Reset timer
0163  * @param timer
0164  */
0165 expublic void ndrx_stopwatch_reset(ndrx_stopwatch_t *timer)
0166 {
0167     clock_gettime(CLOCK_MONOTONIC, &timer->t);
0168 }
0169 
0170 /**
0171  * Set timer.
0172  * The stopwatch will ring when ndrx_stopwatch_get_delta() will be>=0
0173  * 
0174  * @param timer usual stopwatch...
0175  * @param tout timeout in millis
0176  */
0177 expublic void ndrx_stopwatch_timer_set(ndrx_stopwatch_t *timer, int tout)
0178 {
0179     long left_over;
0180     clock_gettime(CLOCK_MONOTONIC, &timer->t);
0181     
0182     timer->t.tv_sec += tout/1000;
0183     /* convert to nanosec*/
0184     left_over = (tout % 1000)*1000000;
0185     
0186     timer->t.tv_nsec+= left_over;
0187     
0188 #define NDRX_NANO_SEC 999999999
0189     
0190     if (timer->t.tv_nsec > NDRX_NANO_SEC)
0191     {
0192         timer->t.tv_sec+=1;
0193         timer->t.tv_nsec-=NDRX_NANO_SEC;
0194     }
0195 }
0196 
0197 /**
0198  * return diff in milliseconds of two timers.
0199  * @param timer1
0200  * @param timer2
0201  * @return diff in milliseconds
0202  */
0203 expublic long long ndrx_stopwatch_diff(ndrx_stopwatch_t *t1, ndrx_stopwatch_t *t2)
0204 {
0205     long long t1r = ((long long)t1->t.tv_sec)*1000 + t1->t.tv_nsec/1000000; /* Convert to milliseconds */
0206     long long t2r = ((long long)t2->t.tv_sec)*1000 + t2->t.tv_nsec/1000000; /* Convert to milliseconds */
0207     long long ret = (t1r-t2r);
0208 /* DEBUG:    NDRX_LOG(log_error, "t1r (%d) = %lld t2r=%lld ret=%lld", t1->t.tv_sec, t1r, t2r, ret); */
0209     return ret;
0210 }
0211 
0212 /**
0213  * Get time spent in milliseconds
0214  * @param timer
0215  * @return time spent in milliseconds
0216  */
0217 expublic long ndrx_stopwatch_get_delta(ndrx_stopwatch_t *timer)
0218 {
0219     struct timespec t;
0220     long ret;
0221 
0222     clock_gettime(CLOCK_MONOTONIC, &t);
0223     
0224     /* calculate delta */
0225     ret = (t.tv_sec - timer->t.tv_sec)*1000 /* Convert to milliseconds */ +
0226                (t.tv_nsec - timer->t.tv_nsec)/1000000; /* Convert to milliseconds */
0227 
0228     return ret;
0229 }
0230 
0231 /**
0232  * Get time spent in seconds
0233  * @param timer
0234  * @return time spent in seconds
0235  */
0236 expublic long ndrx_stopwatch_get_delta_sec(ndrx_stopwatch_t *timer)
0237 {
0238     return (ndrx_stopwatch_get_delta(timer)/1000);
0239 }
0240 
0241 /**
0242  * Timer plus.
0243  * TODO: What to do if msec is <0 ?
0244  * @param timer
0245  * @param msec
0246  * @return 
0247  */
0248 expublic void ndrx_stopwatch_plus(ndrx_stopwatch_t *timer, long long msec)
0249 {
0250     if (msec < 0)
0251     {
0252         ndrx_stopwatch_minus(timer, msec * -1);
0253     }
0254     else 
0255     {
0256         long over = msec % 1000; /* Real milli seconds */
0257         long nsec_tot = over*1000000;
0258         timer->t.tv_sec+= msec/1000;
0259 
0260         if (timer->t.tv_nsec + nsec_tot> 1000000000)
0261         {
0262             timer->t.tv_sec++;
0263             nsec_tot-= 1000000000;
0264         }
0265 
0266         timer->t.tv_nsec+=nsec_tot;
0267     }
0268 }
0269 
0270 /**
0271  * Reduce the time value...
0272  * @param timer
0273  * @param msec
0274  * @return 
0275  */
0276 expublic void ndrx_stopwatch_minus(ndrx_stopwatch_t *timer, long long msec)
0277 {
0278     if (msec < 0)
0279     {
0280         ndrx_stopwatch_plus(timer, msec * -1);
0281     }
0282     else
0283     {
0284         long long over = msec % 1000; /* Real milli seconds */
0285         long long nsec_tot = over*1000000;
0286 
0287         timer->t.tv_sec-= msec/1000;
0288 
0289         if (timer->t.tv_nsec - nsec_tot < 0)
0290         {
0291             timer->t.tv_sec--;
0292             nsec_tot-= 1000000000;
0293         }
0294 
0295         timer->t.tv_nsec-=nsec_tot;
0296     }
0297 }
0298 
0299 /* vim: set ts=4 sw=4 et smartindent: */