<div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Mar 8, 2021 at 2:28 PM Hal Murray via devel <<a href="mailto:devel@ntpsec.org" target="_blank">devel@ntpsec.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I'm poking around in ntp_control because I want to add the CPU time that ntpd <br>
has used for some tests I'm trying to run.<br>
<br>
We have our share of crufty code, but this is the stuff that annoys me the <br>
most.  What should be simple turns into a pain in the ass.<br>
<br>
-------------<br>
<br>
We have several log files that record statistics hourly.  After they write out <br>
a line, they clear the counters.  ntpq can't ask for the totals since restart <br>
- the data is gone.<br>
<br>
James has recently fixed part of that.  ntpq sysstats now prints 2 columns.<br>
<br>
I'd like to open this area up for discussion.<br>
<br>
I'd like the counters behind all log files to keep the totals too.  There are <br>
2 ways to implement that.  One is for the active counters to be the totals.  <br>
The hourly logic would maintain a second copy that holds the value to be <br>
subtracted from the totals to get the this-hour values.  The other is for the <br>
active counters to hold the this-hour values.  To get the totals you would add <br>
the values from the second copy.  I think I prefer the active counters to hold <br>
the totals but I have not strong preferences.<br>
<br>
We need to keep in mind how to make this work in a multi threaded environment.<br></blockquote><div><br></div><div>I think you would need to deglobalize some variables first.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
It would be neat to have 2 more columns - packets per second.  I don't know if <br>
that will fit.<br>
<br>
I'd like to have a ntpq command for each log file.  I like the 2 column <br>
approach.  Currently, the slots in each column have a separate name.  We could <br>
compress that by returning something like:<br>
  foo=23,45678<br>
that is 2 values for one name.<br></blockquote><div><br></div><div>Not until the ramp to 2.0, That screams here lie incompatible changes.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
ntpq could save a copy of the data so it could print the since-xxx values.<br>
<br>
We could get last-day values by saving 24 copies of the last hour data.<br>
<br>
There is at least one comment in ntpq.py saying, roughy, this table should be <br>
in ntpd so that we don't have to edit here too when something changes.  "rv 0" <br>
returns a subset of a big table marked "default".  We could easily add more <br>
flags, one for each log file.<br>
<br>
There is a slight complication.  We need the name that comes back with a <br>
variable to be a meaningful description.</blockquote><div><br></div><div>So, drop the Millsian object notation (or whatever it is called) for something closer to JSON? Protobuf need not apply.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">What's the best way to clean up this mess?  We discussed this before, but I <br>
don't remember any consensus, or anybody stepping up to do their favorite way.<br></blockquote><div><br></div><div>I messed up a little which is where the CV_NAME and CASE_ macros came from.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The current approach needs 3 (I think) tables.  One to define a set of tags, <br>
one to translate the name of each variable to a tag, and the 3rd to print out <br>
the data for that tag.<br></blockquote><div><br></div><div>4+ tables, at least 3 long lists of preprocessor macros, and too much copy/paste code.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
I propose we dump the tags and put everything for each slot into struct.  What does it need?<br>
  name that ntpq uses to ask for this slot<br>
  flags<br>
  pointer to value to be printed<br>
  routine to print it<br>
<br>
We can setup macros to build the struct.<br>
<br>
Does that make sense?<br></blockquote><div> </div><div>Not really, but I am not very effective. I would like to be able to implement something like the following, but it is probably too fussy...<br><br>For example, after butchering all the following it occurred to me that one could just ad a CB (callback) or HOOK value. I mean it is not like there is a sudden lack of space for them.<br></div><div><br></div><div>```py<br></div><div>clock_var_e = {<br>    'name': { RO|DEF|QSTR, 'clockname' },<br>    'timecode': { RO|DEF|QSTR, 'p_lastcode' },<br>    'poll': { RO|DEF|UINT, 'polls' },<br>    'noreply': { RO|DEF|UINT, 'noresponse' },<br>    'badformat': { RO|DEF|UINT, 'badformat' },<br>    'baddata': { RO|DEF|UINT, 'baddata' },<br>    'flags': { RO|DEF|UINT, 'flags' },<br>}<br><br>clock_var_h = {<br>    'fudgetime1': { RO|DEF, clock_do_fudgetime1 },<br>    'fudgetime2': { RO|DEF, clock_do_fudgetime2 },<br>    'stratum': { RO|DEF, clock_do_stratum },<br>    'refid': { RO|DEF, clock_do_refid },<br>    'device': { RO|DEF, clock_do_device },<br>    'clock_var_list': { RO, clock_do_varlist },<br>}<br><br>def read_clockstatus(buffer, statusmask):<br>    if not (REFCLOCK)<br>        ctl_error(CERR_BADASSOC)<br>        return<br><br>    if res_id == 0:<br>        peer = findpeerbyassoc(res_associd);<br>    else:<br>        if sys_vars.sys_peer and FLAG_REFCLOCK&sys_vars.sys_peer.cfg.flags)):<br>            peer = sys_vars.sys_peer;<br>        else:<br>            for (peer = peer_list; peer; peer = peer->p_link):<br>                if (FLAG_REFCLOCK & peer->cfg.flags)<br>                    break;<br>    if not (peer and peer.flags&FLAG_REFCLOCK)<br>        ctl_error(CERR_BADASSOC)<br>        return<br>    refclock_control(&peer->srcadr, NULL, &cs);<br><br>    qset = set()<br>    gotvar = False<br>    iset = set(qstr.split(','))<br>    for key in iset:<br>        if key in clock_var_e or key in clock_var_h:<br>            qset = qset.add(key)<br>        else:<br>            ctl_error(CERR_BADVALUE if key == '' else</div><div>                          CERR_UNKNOWNVAR);<br>            return<br><br>    if gotvar:<br>        // This used to be putclock<br>        if id in clock_var_e:<br>            handler = handlers[clock_var_e[id][0] & FMASK]<br>            handler(id, clock_var_e[id][1])<br>        elif id in clock_var_h:<br>            clock_var_h[id][1](id)<br>    else:<br>        for key in clock_var_e:<br>            if DEF&clock_var_e[key]:<br>                handler = handlers[clock_var_e[id][0] & FMASK]<br>                handler(id, clock_var_e[id][1])        <br>        for key in clock_var_h:<br>            if id in clock_var_h and DEF & clock_var_e[id][0]:<br>                clock_var_h[id][1](id)<br>    flushpkt()</div><div>```<br></div></div></div>