From 0a10da55ab8d5c2ead32f44c1bb4459b014754c7 Mon Sep 17 00:00:00 2001 From: Nichamon Naksinehaboon Date: Sat, 22 Jul 2023 14:08:37 +0700 Subject: [PATCH] Make LDMSD support interval strings The patch makes LDMSD support time-interval strings. A time-interval string is an integer followed by a unit string. A unit string is one of the followings: us -- microseconds ms -- milliseconds s -- seconds min -- minutes hr -- hours day -- days For example, with this patch, to specify a sampling interval of 1 second, '1s' can be used. --- ldms/man/ldmsctl.man | 69 +++++++++++++++++++---- ldms/man/ldmsd_controller.man | 73 ++++++++++++++++++++----- ldms/python/ldmsd/ldmsd_communicator.py | 14 ----- ldms/src/ldmsd/ldmsd.c | 33 ++++++----- ldms/src/ldmsd/ldmsd_prdcr.c | 29 ++++++++-- ldms/src/ldmsd/ldmsd_request.c | 62 ++++++++++++--------- ldms/src/ldmsd/ldmsd_updtr.c | 48 ++++++++-------- lib/src/ovis_util/util.c | 67 +++++++++++++++++++++++ lib/src/ovis_util/util.h | 22 ++++++++ 9 files changed, 311 insertions(+), 106 deletions(-) diff --git a/ldms/man/ldmsctl.man b/ldms/man/ldmsctl.man index a9d4055d3..18718780d 100644 --- a/ldms/man/ldmsctl.man +++ b/ldms/man/ldmsctl.man @@ -166,11 +166,20 @@ The plugin name. .TP .BI interval " interval" .br -The sample interval in microseconds. +The sample interval, which is an integer, followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI [offset " offset"] .br -Offset (shift) from the sample mark in microseconds. +Offset (shift) from the sample mark. The value is an integer, +followed by a unit string. Offset can be positive or negative with magnitude up to 1/2 the sample interval. If this offset is specified, including 0, collection will be synchronous; if the offset is not specified, @@ -214,7 +223,15 @@ The connection type [active, passive] .TP .BI reconnect " interval" .br -The connection retry interval +The connection retry interval, which is an integer, followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI interval " interval" .br @@ -248,8 +265,16 @@ The producer name .TP .BI [interval " interval"] .br -The connection retry interval in microsec. If unspecified, -the previously configured value will be used. Optional. +The connection retry interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If unspecified, the previously configured value will be used. Optional. .RE .SS Start all producers matching a regular expression @@ -263,8 +288,16 @@ A regular expression .TP .BI [interval " interval"] .br -The connection retry interval in microsec. If unspecified, -the previously configured value will be used. Optional. +The connection retry interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If unspecified, the previously configured value will be used. Optional. .RE .SS Stop a producer @@ -325,7 +358,15 @@ any attributes specified for the metric sets or hosts. .TP .BI interval " interval" .br -The update/collect interval +The update/collect interval, which is an integer, followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI [offset " offset"] .br @@ -442,8 +483,16 @@ The update policy name .TP .BI [interval " interval"] .br -The update interval in micro-seconds. If this is not -specified, the previously configured value will be used. Optional. +The update interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If this is not specified, the previously configured value will be used. Optional. .TP .BI [offset " offset"] .br diff --git a/ldms/man/ldmsd_controller.man b/ldms/man/ldmsd_controller.man index 2941f3d8c..f301819df 100644 --- a/ldms/man/ldmsd_controller.man +++ b/ldms/man/ldmsd_controller.man @@ -166,15 +166,22 @@ The plugin name. .TP .BI interval " interval" .br -The sample interval in microseconds. +The sample interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI [offset " offset"] .br -Offset (shift) from the sample mark in microseconds. +Offset (shift) from the sample mark in the same format as intervals. Offset can be positive or negative with magnitude up to 1/2 -the sample interval. If this offset is specified, including 0, -collection will be synchronous; if the offset is not specified, -collection will be asynchronous. Optional. +the sample interval. The default offset is 0. Collection is always synchronous. + .RE @@ -269,7 +276,15 @@ The connection type [active, passive] .TP .BI reconnect " interval" .br -The connection retry interval +The connection retry interval, which is an integer, followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI interval " interval" .br @@ -321,8 +336,16 @@ The producer name .TP .BI [interval " interval"] .br -The connection retry interval in microsec. If unspecified, -the previously configured value will be used. Optional. +The connection retry interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If unspecified, the previously configured value will be used. Optional. .RE .SS Start all producers matching a regular expression @@ -336,8 +359,16 @@ A regular expression .TP .BI [interval " interval"] .br -The connection retry interval in microsec. If unspecified, -the previously configured value will be used. Optional. +The connection retry interval, which is an integer followed by a unit stirng. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If unspecified, the previously configured value will be used. Optional. .RE .SS Stop a producer @@ -397,7 +428,15 @@ any attributes specified for the metric sets or hosts. .TP .BI interval " interval" .br -The update/collect interval +The update/collect interval, which is an integer, followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days .TP .BI [offset " offset"] .br @@ -514,8 +553,16 @@ The update policy name .TP .BI [interval " interval"] .br -The update interval in micro-seconds. If this is not -specified, the previously configured value will be used. Optional. +The update interval, which is an integer followed by a unit string. +If no unit string is given, the default unit is microseconds. +A unit string is one of the followings: + us -- microseconds + ms -- milliseconds + s -- seconds + min -- minutes + hr -- hours + day -- days +If this is not specified, the previously configured value will be used. Optional. .TP .BI [offset " offset"] .br diff --git a/ldms/python/ldmsd/ldmsd_communicator.py b/ldms/python/ldmsd/ldmsd_communicator.py index 92c5af710..0308d5333 100644 --- a/ldms/python/ldmsd/ldmsd_communicator.py +++ b/ldms/python/ldmsd/ldmsd_communicator.py @@ -204,17 +204,6 @@ 'auth_add': {'req_attr': ['name', 'plugin'], 'opt_attr': []}, } -def check_offset(interval_us, offset_us=None): - """ - Ensure that offset provided is valid for ldmsd with given interval - """ - if offset_us: - interval_us = int(interval_us) - offset_us = int(offset_us) - if offset_us/interval_us > .5: - offset_us = interval_us/2 - return offset_us - def fmt_status(msg): """ Format communicator status response string into json object @@ -2027,7 +2016,6 @@ def plugn_start(self, name, interval_us, offset_us=None): LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.INTERVAL, value=str(interval_us)) ] if offset_us != None: - offset_us = check_offset(interval_us, offset_us) req_attrs.append(LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.OFFSET, value=str(offset_us))) req = LDMSD_Request( command_id = LDMSD_Request.PLUGN_START, @@ -2406,7 +2394,6 @@ def updtr_add(self, name, interval=1000000, offset=None, push=None, auto=None, p attrs += [ LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.INTERVAL, value=str(interval)) ] - offset = check_offset(interval, offset) if offset: attrs += [ LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.OFFSET, value=str(offset)) @@ -2510,7 +2497,6 @@ def updtr_start(self, name, interval=None, offset=None, auto_interval=None): LDMSD_Req_Attr(attr_id=LDMSD_Req_Attr.NAME, value=name), ] if interval: - offset = check_offset(interval, offset) if auto_interval: return errno.EINVAL, "'auto' is incompatible with 'interval'" attrs += [ diff --git a/ldms/src/ldmsd/ldmsd.c b/ldms/src/ldmsd/ldmsd.c index a8eb9b70c..b6ff419fa 100644 --- a/ldms/src/ldmsd/ldmsd.c +++ b/ldms/src/ldmsd/ldmsd.c @@ -1075,20 +1075,13 @@ void ldmsd_set_info_delete(ldmsd_set_info_t info) free(info); } -int __sampler_set_info_add(struct ldmsd_plugin *pi, char *interval, char *offset) +int __sampler_set_info_add(struct ldmsd_plugin *pi, long interval_us, long offset_us) { ldmsd_plugin_set_t set; int rc; - long interval_us; - long offset_us = 0; if (pi->type != LDMSD_PLUGIN_SAMPLER) return EINVAL; - if (!interval) - return EINVAL; - interval_us = strtol(interval, NULL, 0); - if (offset) - offset_us = strtol(offset, NULL, 0); for (set = ldmsd_plugin_set_first(pi->name); set; set = ldmsd_plugin_set_next(set)) { rc = ldmsd_set_update_hint_set(set->set, interval_us, offset_us); @@ -1107,15 +1100,14 @@ int __sampler_set_info_add(struct ldmsd_plugin *pi, char *interval, char *offset */ int ldmsd_start_sampler(char *plugin_name, char *interval, char *offset) { - char *endptr; int rc = 0; long sample_interval; long sample_offset = 0; struct ldmsd_plugin_cfg *pi; - sample_interval = strtol(interval, &endptr, 0); - if ((endptr[0] != '\0') || (sample_interval <= 0)) - return EINVAL; + rc = ovis_time_str2us(interval, &sample_interval); + if (rc) + return rc; pi = ldmsd_get_plugin((char *)plugin_name); if (!pi) @@ -1131,19 +1123,26 @@ int ldmsd_start_sampler(char *plugin_name, char *interval, char *offset) goto out; } - rc = __sampler_set_info_add(pi->plugin, interval, offset); - if (rc) - goto out; pi->sample_interval_us = sample_interval; if (offset) { - sample_offset = strtol(offset, NULL, 0); + rc = ovis_time_str2us(offset, &sample_offset); + if (rc) { + rc = EDOM; + goto out; + } if ( !((sample_interval >= 10) && (sample_interval >= labs(sample_offset)*2)) ){ - rc = EDOM; + rc = -EDOM; goto out; } } pi->sample_offset_us = sample_offset; + + rc = __sampler_set_info_add(pi->plugin, sample_interval, + sample_offset); + if (rc) + goto out; + OVIS_EVENT_INIT(&pi->oev); pi->oev.param.type = OVIS_EVENT_PERIODIC; pi->oev.param.periodic.period_us = sample_interval; diff --git a/ldms/src/ldmsd/ldmsd_prdcr.c b/ldms/src/ldmsd/ldmsd_prdcr.c index bd43ea991..f50552177 100644 --- a/ldms/src/ldmsd/ldmsd_prdcr.c +++ b/ldms/src/ldmsd/ldmsd_prdcr.c @@ -950,11 +950,18 @@ int ldmsd_prdcr_start(const char *name, const char *interval_str, ldmsd_sec_ctxt_t ctxt) { int rc = 0; + long reconnect; ldmsd_prdcr_t prdcr = ldmsd_prdcr_find(name); if (!prdcr) return ENOENT; - if (interval_str) - prdcr->conn_intrvl_us = strtol(interval_str, NULL, 0); + if (interval_str) { + rc = ovis_time_str2us(interval_str, &reconnect); + if (rc) + return EINVAL; + if (reconnect <= 0) + return -EINVAL; + prdcr->conn_intrvl_us = reconnect; + } rc = __ldmsd_prdcr_start(prdcr, ctxt); ldmsd_prdcr_put(prdcr); return rc; @@ -1176,6 +1183,20 @@ int ldmsd_prdcr_start_regex(const char *prdcr_regex, const char *interval_str, regex_t regex; ldmsd_prdcr_t prdcr; int rc; + long reconnect; + + if (interval_str) { + rc = ovis_time_str2us(interval_str, &reconnect); + if (rc) { + snprintf(rep_buf, rep_len, "The reconnect interval value " + "(%s) is invalid.", interval_str); + return EINVAL; + } + if (reconnect <= 0) { + snprintf(rep_buf, rep_len, "The reconnect interval must be a positive interval."); + return EINVAL; + } + } rc = ldmsd_compile_regex(®ex, prdcr_regex, rep_buf, rep_len); if (rc) @@ -1187,12 +1208,12 @@ int ldmsd_prdcr_start_regex(const char *prdcr_regex, const char *interval_str, if (rc) continue; if (interval_str) - prdcr->conn_intrvl_us = strtol(interval_str, NULL, 0); + prdcr->conn_intrvl_us = reconnect; __ldmsd_prdcr_start(prdcr, ctxt); } ldmsd_cfg_unlock(LDMSD_CFGOBJ_PRDCR); regfree(®ex); - return 0; + return rc; } int ldmsd_prdcr_stop_regex(const char *prdcr_regex, char *rep_buf, diff --git a/ldms/src/ldmsd/ldmsd_request.c b/ldms/src/ldmsd/ldmsd_request.c index 576657c00..6b20c18e1 100644 --- a/ldms/src/ldmsd/ldmsd_request.c +++ b/ldms/src/ldmsd/ldmsd_request.c @@ -1488,7 +1488,7 @@ static int prdcr_add_handler(ldmsd_req_ctxt_t reqc) char *auth; enum ldmsd_prdcr_type type = -1; unsigned short port_no = 0; - int interval_us = -1; + long interval_us = -1; size_t cnt; uid_t uid; gid_t gid; @@ -1561,12 +1561,16 @@ static int prdcr_add_handler(ldmsd_req_ctxt_t reqc) if (!interval_s) { goto einval; } else { - char *ptr; - interval_us = strtol(interval_s, &ptr, 0); - if ((*interval_s == '\0') || (*ptr != '\0') || (interval_us <= 0)) { + reqc->errcode = ovis_time_str2us(interval_s, &interval_us); + if (reqc->errcode) { + cnt = snprintf(reqc->line_buf, reqc->line_len, + "The given 'reconnect' is invalid."); + goto send_reply; + } + if (interval_us <= 0) { reqc->errcode = EINVAL; cnt = snprintf(reqc->line_buf, reqc->line_len, - "The 'reconnect' value must be a positive number."); + "The reconnect interval must be a positive number."); goto send_reply; } } @@ -1618,7 +1622,7 @@ static int prdcr_add_handler(ldmsd_req_ctxt_t reqc) goto enomem; } __dlog(DLOG_CFGOK, "prdcr_add name=%s xprt=%s host=%s port=%u type=%s " - "interval=%d auth=%s uid=%d gid=%d perm=%o\n", + "interval=%ld auth=%s uid=%d gid=%d perm=%o\n", name, xprt, host, port_no, type_s, interval_us, auth ? auth : "none", (int)uid, (int)gid, (unsigned)perm); @@ -1748,6 +1752,14 @@ static int prdcr_start_handler(ldmsd_req_ctxt_t reqc) Snprintf(&reqc->line_buf, &reqc->line_len, "Permission denied."); break; + case EINVAL: + cnt = Snprintf(&reqc->line_buf, &reqc->line_len, + "The 'reconnect' value (%s) is invalid.", interval_str); + break; + case -EINVAL: + cnt = Snprintf(&reqc->line_buf, &reqc->line_len, + "The 'reconnect' interval must be a positive interval."); + break; default: Snprintf(&reqc->line_buf, &reqc->line_len, "Error: %d %s", @@ -3223,7 +3235,6 @@ static int updtr_add_handler(ldmsd_req_ctxt_t reqc) gid_t gid; int perm; char *perm_s = NULL; - char *endptr; int push_flags, is_auto_task; long interval, offset; @@ -3264,11 +3275,10 @@ static int updtr_add_handler(ldmsd_req_ctxt_t reqc) "an empty string."); goto send_reply; } - interval = strtol(interval_str, &endptr, 0); - if ('\0' != endptr[0]) { - reqc->errcode = EINVAL; + reqc->errcode = ovis_time_str2us(interval_str, &interval); + if (reqc->errcode) { cnt = Snprintf(&reqc->line_buf, &reqc->line_len, - "The given update interval value (%s) is not a number.", + "The given update interval value (%s) is invalid.", interval_str); goto send_reply; } else { @@ -3293,12 +3303,11 @@ static int updtr_add_handler(ldmsd_req_ctxt_t reqc) "The given update offset value is an empty string."); goto send_reply; } - offset = strtol(offset_str, &endptr, 0); - if ('\0' != endptr[0]) { - reqc->errcode = EINVAL; + reqc->errcode = ovis_time_str2us(offset_str, &offset); + if (reqc->errcode) { cnt = Snprintf(&reqc->line_buf, &reqc->line_len, "The given update offset value (%s) " - "is not a number.", offset_str); + "is invalid.", offset_str); goto send_reply; } if (interval_str && (interval < labs(offset) * 2)) { @@ -3856,7 +3865,6 @@ static int updtr_start_handler(ldmsd_req_ctxt_t reqc) char *updtr_name, *interval_str, *offset_str, *auto_interval; updtr_name = interval_str = offset_str = auto_interval = NULL; size_t cnt = 0; - char *endptr; long interval, offset = 0; struct ldmsd_sec_ctxt sctxt; @@ -3880,12 +3888,11 @@ static int updtr_start_handler(ldmsd_req_ctxt_t reqc) "The given update offset value is an empty string."); goto send_reply; } - offset = strtol(offset_str, &endptr, 0); - if ('\0' != endptr[0]) { - reqc->errcode = EINVAL; + reqc->errcode = ovis_time_str2us(offset_str, &offset); + if (reqc->errcode) { cnt = Snprintf(&reqc->line_buf, &reqc->line_len, "The given update offset value (%s) " - "is not a number.", offset_str); + "is invalid.", offset_str); goto send_reply; } } @@ -3898,19 +3905,18 @@ static int updtr_start_handler(ldmsd_req_ctxt_t reqc) "an empty string."); goto send_reply; } - interval = strtol(interval_str, &endptr, 0); - if ('\0' != endptr[0]) { - reqc->errcode = EINVAL; + reqc->errcode = ovis_time_str2us(interval_str, &interval); + if (reqc->errcode) { cnt = Snprintf(&reqc->line_buf, &reqc->line_len, - "The given update interval value (%s) is not a number.", + "The given update interval value (%s) is invalid.", interval_str); goto send_reply; } else { if (0 >= interval) { reqc->errcode = EINVAL; cnt = Snprintf(&reqc->line_buf, &reqc->line_len, - "The update interval value must " - "be larger than 0. (%ld)", interval); + "The update interval must " + "be a positive interval. (%ld)", interval); goto send_reply; } if (offset_str && interval < labs(offset) * 2) { @@ -4918,6 +4924,10 @@ static int plugn_start_handler(ldmsd_req_ctxt_t reqc) cnt = Snprintf(&reqc->line_buf, &reqc->line_len, "Sampler '%s' is already running.", plugin_name); } else if (reqc->errcode == EDOM) { + reqc->errcode = EINVAL; + cnt = Snprintf(&reqc->line_buf, &reqc->line_len, + "The given 'offset' (%s) is invalid.", offset); + } else if (reqc->errcode == -EDOM) { reqc->errcode = EINVAL; cnt = Snprintf(&reqc->line_buf, &reqc->line_len, "Sampler parameters interval and offset are " diff --git a/ldms/src/ldmsd/ldmsd_updtr.c b/ldms/src/ldmsd/ldmsd_updtr.c index b4ad5b0d5..6ba4fc140 100644 --- a/ldms/src/ldmsd/ldmsd_updtr.c +++ b/ldms/src/ldmsd/ldmsd_updtr.c @@ -927,8 +927,8 @@ ldmsd_updtr_new_with_auth(const char *name, char *interval_str, char *offset_str int push_flags, int is_auto_task, uid_t uid, gid_t gid, int perm) { + int rc; struct ldmsd_updtr *updtr; - char *endptr; long interval_us = UPDTR_TREE_MGMT_TASK_INTRVL, offset_us = LDMSD_UPDT_HINT_OFFSET_NONE; updtr = (struct ldmsd_updtr *) ldmsd_cfgobj_new_with_auth(name, LDMSD_CFGOBJ_UPDTR, @@ -941,16 +941,12 @@ ldmsd_updtr_new_with_auth(const char *name, char *interval_str, char *offset_str updtr->default_task.is_default = 1; updtr->is_auto_task = is_auto_task; if (interval_str) { - interval_us = strtol(interval_str, &endptr, 0); - if (('\0' == interval_str[0]) || ('\0' != endptr[0])) - goto einval; - if (0 >= interval_us) + rc = ovis_time_str2us(interval_str, &interval_us); + if (rc || (0 >= interval_us)) goto einval; if (offset_str) { - offset_us = strtol(offset_str, &endptr, 0); - if (('\0' == offset_str[0]) || ('\0' != endptr[0])) - goto einval; - if (interval_us < labs(offset_us) * 2) + rc = ovis_time_str2us(offset_str, &offset_us); + if (rc || (interval_us < labs(offset_us) * 2)) goto einval; /* Make it a hint offset */ offset_us -= updtr_sched_offset_skew_get(); @@ -1097,8 +1093,12 @@ int ldmsd_updtr_start(const char *updtr_name, const char *interval_str, interval_us = updtr->default_task.sched.intrvl_us; offset_us = updtr->default_task.hint.offset_us; if (interval_str) { - /* A new interval is given. */ - interval_us = strtol(interval_str, NULL, 0); + /* A new interval is given, and its value has been checked by the handler. */ + rc = ovis_time_str2us(interval_str, &interval_us); + if (rc || (interval_us <= 0)) { + rc = EINVAL; + goto err; + } if (!offset_str) { /* An offset isn't given. We assume that * users want the updater to schedule asynchronously. @@ -1106,17 +1106,21 @@ int ldmsd_updtr_start(const char *updtr_name, const char *interval_str, offset_us = LDMSD_UPDT_HINT_OFFSET_NONE; } } - if (offset_str) - offset_us = strtol(offset_str, NULL, 0) - - updtr_sched_offset_skew_get(); - - if (interval_us < labs(offset_us) * 2) { - ovis_log(updtr_log, OVIS_LERROR, "%s: The absolute value of the offset" - " value must not be larger than the half of " - "the update interval. (i=%ld, o=%ld)\n", "ldmsd_updtr_start", - interval_us, offset_us); - rc = EINVAL; - goto err; + if (offset_str) { + rc = ovis_time_str2us(offset_str, &offset_us); + if (rc) { + rc = EINVAL; + goto err; + } + if (interval_us < labs(offset_us) * 2) { + ovis_log(updtr_log, OVIS_LERROR, "%s: The absolute value of the offset" + " value must not be larger than the half of " + "the update interval. (i=%ld, o=%ld)\n", "ldmsd_updtr_start", + interval_us, offset_us); + rc = EINVAL; + goto err; + } + offset_us = offset_us - updtr_sched_offset_skew_get(); } /* Initialize the default task */ updtr_task_init(&updtr->default_task, updtr, 1, interval_us, offset_us); diff --git a/lib/src/ovis_util/util.c b/lib/src/ovis_util/util.c index 9c9ae5d0a..b6d12df88 100644 --- a/lib/src/ovis_util/util.c +++ b/lib/src/ovis_util/util.c @@ -597,6 +597,73 @@ size_t ovis_get_mem_size(const char *s) } } +/* + * microseconds: us, microsecond(s) + * milliseconnds: ms, millisecond(s) + * seconds: s, sec, second(s) + * minutes: min, minutes(s) + * hours: h, hr(s), hour(s) + * days: day(s) + */ +int ovis_time_str2us(const char *s, long *v) +{ + char *unit; + long x; + + x = strtol(s, &unit, 0); + if (unit == s) + return EINVAL; + + while (unit[0] == ' ') + unit++; + + if ((unit[0] == '\0') || (0 == strcmp(unit, "us")) || (0 == strncmp(unit, "micro", 5))) { + /* microseconds */ + *v = x; + } else if ((0 == strcmp(unit, "ms")) || (0 == strncmp(unit, "milli", 5))) { + /* milliseconds */ + *v = x * 1000; + } else if ((0 == strcmp(unit, "s")) || (0 == strncmp(unit, "sec", 3))) { + /* seconds */ + *v = x * 1000000; + } else if (0 == strncmp(unit, "min", 3)) { + /* minutes */ + *v = x * 1000000 * 60; + } else if (unit[0] == 'h') { + /* hours */ + *v = x * 1000000 * 60 * 60; + } else if (0 == strncmp(unit, "day", 3)) { + /* days */ + *v = x * 1000000 * 60 * 60 * 24; + } else { + return EINVAL; + } + return 0; +} + +long ovis_interval_str2long(const char *s) +{ + char unit; + size_t n = strlen(s) + 3; + char tmp[n]; + snprintf(tmp, n, "%s%s", s, "u"); /* Default is usec */ + uint64_t value; + + sscanf(tmp, "%lu%c", &value, &unit); + switch (unit) { + case 's': /* seconds */ + return value * 1000000.0; + case 'm': /* milliseconnds */ + return value * 1000.0; + case 'u': /* microseconds */ + return value * 1.0; + case 'n': /* nanoseconds */ + return value / 1000.0; + default: + return 0; + } +} + pid_t ovis_execute(const char *command) { char *argv[] = {"/bin/sh", "-c", (char*)command, NULL}; diff --git a/lib/src/ovis_util/util.h b/lib/src/ovis_util/util.h index e9256b336..7b53de7c5 100644 --- a/lib/src/ovis_util/util.h +++ b/lib/src/ovis_util/util.h @@ -193,6 +193,28 @@ int av_check_expansion(printf_t log, const char *name, const char *value); */ size_t ovis_get_mem_size(const char *s); +/** + * \brief Convert a time-interval string to microseconds + * + * A time-interval string is an integer followed by a unit string. + * A unit string is one of the following: + * + * 'us' - microseconds + * 'ms' - milliseconds + * 's' - seconds + * 'min' - minutes + * 'h','hr' - hours + * 'day' - days + * + * If no unit string is given, the default unit is microseconds. + * + * \param s a string to be converted. The valid format is