xref: /dragonfly/usr.bin/dsynth/runstats.c (revision 51705b282e410aa91b8f9a3be97c1de2f3154ac0)
1 /*
2  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "dsynth.h"
39 
40 static runstats_t *RSBase;
41 static runstats_t **RSTailp = &RSBase;
42 static time_t RSStartTime;
43 
44 #define RHISTSIZE       600             /* impulse record is 10 minutes */
45 #define ONEHOUR               (60 * 60)
46 
47 void
RunStatsInit(void)48 RunStatsInit(void)
49 {
50           runstats_t *rs;
51 
52           RSStartTime = time(NULL);
53 
54           *RSTailp = &NCursesRunStats;
55           RSTailp = &(*RSTailp)->next;
56 
57           *RSTailp = &MonitorRunStats;
58           RSTailp = &(*RSTailp)->next;
59 
60           *RSTailp = &HtmlRunStats;
61           RSTailp = &(*RSTailp)->next;
62 
63           for (rs = RSBase; rs; rs = rs->next)
64                     rs->init();
65 }
66 
67 void
RunStatsDone(void)68 RunStatsDone(void)
69 {
70           runstats_t *rs;
71 
72           for (rs = RSBase; rs; rs = rs->next)
73                     rs->done();
74 }
75 
76 void
RunStatsReset(void)77 RunStatsReset(void)
78 {
79           runstats_t *rs;
80 
81           for (rs = RSBase; rs; rs = rs->next)
82                     rs->reset();
83 }
84 
85 void
RunStatsUpdate(worker_t * work,const char * portdir)86 RunStatsUpdate(worker_t *work, const char *portdir)
87 {
88           runstats_t *rs;
89 
90           for (rs = RSBase; rs; rs = rs->next)
91                     rs->update(work, portdir);
92 }
93 
94 void
RunStatsUpdateTop(int active)95 RunStatsUpdateTop(int active)
96 {
97           static int rate_history[RHISTSIZE];
98           static u_int last_ti;
99           topinfo_t info;
100           runstats_t *rs;
101           u_int ti;
102           time_t t;
103 
104           /*
105            * Time
106            */
107           bzero(&info, sizeof(info));
108           t = time(NULL) - RSStartTime;
109           info.s = t % 60;
110           info.m = t / 60 % 60;
111           info.h = t / 60 / 60;
112           info.active = active;
113 
114           /*
115            * Easy fields
116            */
117           info.total = BuildTotal;
118           info.successful = BuildSuccessCount;
119           info.ignored = BuildIgnoreCount;
120           info.remaining = BuildTotal - BuildCount;
121           info.failed = BuildFailCount;
122           info.skipped = BuildSkipCount;
123           info.meta = BuildMetaCount;
124 
125           /*
126            * Load and swap
127            */
128           getloadavg(info.dload, 3);
129           info.dswap = getswappct(&info.noswap) * 100.0;
130 
131           /*
132            * Rate and 10-minute impulse
133            */
134           if (t > 20)
135                     info.pkgrate = (BuildSuccessCount + BuildFailCount) *
136                                      ONEHOUR / t;
137           else
138                     info.pkgrate = 0;
139           ti = (u_int)((unsigned long)t % RHISTSIZE);
140           rate_history[ti] = BuildSuccessCount + BuildFailCount;
141 #if 0
142           dlog(DLOG_ALL, "ti[%3d] = %d\n", ti, rate_history[ti]);
143 #endif
144           while (last_ti != ti) {
145                     rate_history[last_ti] = rate_history[ti];
146                     last_ti = (last_ti + 1) % RHISTSIZE;
147           }
148 
149           if (t < 20) {
150                     info.pkgimpulse = 0;
151           } else if (t < RHISTSIZE) {
152                     info.pkgimpulse = rate_history[ti] -
153                                           rate_history[(ti - t) % RHISTSIZE];
154                     info.pkgimpulse = info.pkgimpulse * ONEHOUR / t;
155           } else {
156                     info.pkgimpulse = rate_history[ti] -
157                                           rate_history[(ti + 1) % RHISTSIZE];
158                     info.pkgimpulse = info.pkgimpulse * ONEHOUR / RHISTSIZE;
159 #if 0
160                     dlog(DLOG_ALL, "pkgimpulse %d - %d -> %d\n",
161                          rate_history[ti],
162                          rate_history[(ti + 1) % RHISTSIZE],
163                          info.pkgimpulse);
164 #endif
165           }
166 
167           info.dynmaxworkers = DynamicMaxWorkers;
168 
169           /*
170            * Issue update
171            */
172           for (rs = RSBase; rs; rs = rs->next)
173                     rs->updateTop(&info);
174 }
175 
176 void
RunStatsUpdateLogs(void)177 RunStatsUpdateLogs(void)
178 {
179           runstats_t *rs;
180 
181           for (rs = RSBase; rs; rs = rs->next)
182                     rs->updateLogs();
183 }
184 
185 void
RunStatsSync(void)186 RunStatsSync(void)
187 {
188           runstats_t *rs;
189 
190           for (rs = RSBase; rs; rs = rs->next)
191                     rs->sync();
192 }
193 
194 void
RunStatsUpdateCompletion(worker_t * work,int logid,pkg_t * pkg,const char * reason,const char * skipbuf)195 RunStatsUpdateCompletion(worker_t *work, int logid, pkg_t *pkg,
196                                const char *reason, const char *skipbuf)
197 {
198           runstats_t *rs;
199 
200           for (rs = RSBase; rs; rs = rs->next) {
201                     if (rs->updateCompletion)
202                               rs->updateCompletion(work, logid, pkg, reason, skipbuf);
203           }
204 }
205