<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>